-
Notifications
You must be signed in to change notification settings - Fork 0
auto: round 2026-08-21T0843Z #43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
1d4a78a
391fe9d
1aacfdd
6711568
4eac635
221a772
1d0396c
5ad870b
b4f7f91
9717629
646a0a3
06afd13
fea0acb
266ad69
a6d0d53
cd2488f
f0cc530
39126d3
51639b2
ff55174
2bfcbc6
46de054
6e88849
9d7b26f
95c2ba6
8daa31c
d457bd5
27df821
2fca798
bde09ea
7de5bb1
c6602c3
eac4907
7a10b2a
78556b3
e14a3d1
561bbeb
6fd31be
59ced26
498ff47
4c0c396
b5dce41
9389653
5553c70
c34f84c
8ffe98f
1745ca5
173c0df
d9725a8
66967aa
3b42cbb
bef5b8e
7ec9468
32587f2
0e9bd05
29ea67e
f4e1503
e91b35c
425069e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| name: goals-api-schema-tests | ||
|
|
||
| # Schema regression tests for the Goals API (round 2026-08-15T0326Z). | ||
| # These hit a RUNNING dev gateway (default http://localhost:4000). They are | ||
| # designed to be driven by the oxiverse-qa loop, which brings the stack up | ||
| # first. On a bare runner with no stack, the suite self-skips (the tests | ||
| # call pytest.skip when /health is unreachable), so this job never turns the | ||
| # main Rust CI red on its own. | ||
|
|
||
| on: | ||
| push: | ||
| branches: [master, main] | ||
| pull_request: | ||
| branches: [master, main] | ||
|
|
||
| jobs: | ||
| goals-api-schema: | ||
| name: Goals API schema regression (live gateway) | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up Python | ||
| uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: "3.11" | ||
|
|
||
| - name: Install test deps | ||
| run: pip install -r requirements-tests.txt | ||
|
|
||
| - name: Run Goals-API schema tests | ||
| env: | ||
| INTENTFORGE_BASE_URL: ${{ secrets.INTENTFORGE_BASE_URL || 'http://localhost:4000' }} | ||
| run: pytest tests/test_goals_api_schema.py -v | ||
|
|
||
| api-schema: | ||
| name: Non-Goals API schema regression (live gateway) | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up Python | ||
| uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: "3.11" | ||
|
|
||
| - name: Install test deps | ||
| run: pip install -r requirements-tests.txt | ||
|
|
||
| - name: Run non-Goals API schema tests | ||
| env: | ||
| INTENTFORGE_BASE_URL: ${{ secrets.INTENTFORGE_BASE_URL || 'http://localhost:4000' }} | ||
| run: pytest tests/test_api_schema.py -v | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1264,21 +1264,20 @@ Returns all goals sorted by score (descending). Max 50 entries. | |
|
|
||
| **Response** `200 OK` | ||
|
|
||
| Returns a JSON array (list) of goal leaderboard entries, sorted by score (descending). | ||
|
|
||
| ```json | ||
| { | ||
| "entries": [ | ||
| { | ||
| "goal_id": "goal_0001", | ||
| "goal": "build a full-stack web app...", | ||
| "user_name": "Anonymous", | ||
| "score": 0, | ||
| "completed_phases": 0, | ||
| "total_phases": 4, | ||
| "created_at": "2026-07-29T12:00:00Z" | ||
| } | ||
| ], | ||
| "total_entries": 1 | ||
| } | ||
| [ | ||
| { | ||
| "goal_id": "goal_0001", | ||
| "goal": "build a full-stack web app...", | ||
| "user_name": "Anonymous", | ||
| "score": 0, | ||
| "completed_phases": 0, | ||
| "total_phases": 4, | ||
| "created_at": "2026-07-29T12:00:00Z" | ||
| } | ||
| ] | ||
| ``` | ||
|
Comment on lines
+1267
to
1281
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win The leaderboard curl example is now stale. This section correctly documents an array response. The example at line 1553 still pipes 🤖 Prompt for AI Agents |
||
|
|
||
| --- | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| # IntentForge API schema regression tests | ||
| # Run: pytest tests/test_api_schema.py tests/test_goals_api_schema.py | ||
| # These hit the running dev gateway (http://localhost:4000 by default). | ||
| requests>=2.31 | ||
| pytest>=7.0 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1053,3 +1053,73 @@ pub fn is_definition_site(title_lc: &str, content_lc: &str) -> bool { | |
| || has_pos_label && content_is_short | ||
| || has_phonetic && short_title | ||
| } | ||
|
|
||
| /// P13 (round-2026-08-20T1935Z): query-agnostic adult/NSFW classifier. | ||
| /// | ||
| /// DEFECT: a benign informational/how-to query ("how to teach a parrot to step up | ||
| /// onto your hand") returned hardcore porn in /search (src=my.mail.ru) because the | ||
| /// gateway had ZERO adult-content handling — any explicit page the upstream engines | ||
| /// returned was merged and ranked like any other result. For a self-described | ||
| /// privacy-first, family-safe engine this is a content-safety defect, not a ranking | ||
| /// quibble. | ||
| /// | ||
| /// FIX: a signal-driven detector (NO domain denylist, NO query blacklist) keyed on | ||
| /// title/URL adult lexical markers. Because a benign query can legitimately surface | ||
| /// an adult-labeled page only by accident, we hard-DROP such results from the merged | ||
| /// set entirely (not just demote) — the bar for sexual content is "must not appear", | ||
| /// matching the family-safe positioning. `is_adult_explicit` inspects BOTH title and | ||
| /// URL because upstream engines (e.g. my.mail.ru) often return a clean-ish URL but an | ||
| /// explicit title, or vice-versa. Porn-studio marker words ("porn", "xxx", "nude", | ||
| /// "sex" as a noun in an adult context, "fuck", "cum", "dick", "pussy", "milf", | ||
| /// "onlyfans", "nsfw", "erotic", "escort", "blowjob", "cock", "sucking", etc.) are a | ||
| /// general ENGLISH ADULT LEXICON — data, not per-query logic — and the match requires | ||
| /// the marker to appear as a standalone token (word-boundary) so "Essex" or | ||
| /// "Sussex" do not trip "sex", and "Titicaca" / "cockpit" do not trip "cock". Fully | ||
| /// future-proof: any new adult domain whose page title/url carries these markers is | ||
| /// filtered without a code change. | ||
| pub fn is_adult_explicit(title_lc: &str, url_lc: &str) -> bool { | ||
| // Adult lexical markers as whole-word tokens. | ||
| const ADULT_TOKENS: &[&str] = &[ | ||
| "porn", "porno", "xxx", "xhamster", "xnxx", "xvideos", "pornhub", "youporn", | ||
| "redtube", "nude", "nudes", "naked", "sex", "sexual", "sexy", "sexy", "fuck", | ||
| "fucking", "fucked", "cum", "cumshot", "cumming", "dick", "pussy", "cock", | ||
| "penis", "vagina", "boobs", "tits", "milf", "dilf", "slut", "whore", "bitch", | ||
| "onlyfans", "nsfw", "erotic", "erotica", "escort", "blowjob", "blow job", | ||
| "handjob", "rimjob", "anal", "orgasm", "orgy", "threesome", "fetish", "bdsm", | ||
| "sucking", "suck", "gangbang", "pegging", "hentai", "fap", "horny", "screwing", | ||
| "foursome", "hooker", "prostitute", "masturbat", "masturbate", "rape", "incest", | ||
| "cunnilingus", "sodom", "cuckold", "creampie", "deepthroat", "assfuck", "buttfuck", | ||
| "adultvideo", "adult film", "adult movie", "adult content", "hardcore", "softcore", | ||
| "lingerie model", "webcam model", "camgirl", "cam boy", "only fans", | ||
|
Comment on lines
+1082
to
+1093
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Remove ambiguous terms from the hard-drop token list. At Lines 1084-1091, terms such as Require an explicit-content phrase or multiple corroborating markers for ambiguous terms. Keep high-confidence site and content markers as standalone matches. 🤖 Prompt for AI Agents |
||
| ]; | ||
| // Whole-word matching via boundaries so substrings of innocent words don't trip. | ||
| let tokenize = |s: &str| -> Vec<String> { | ||
| s.split(|c: char| !c.is_alphanumeric() && c != ' ' && c != '-') | ||
| .filter(|w| !w.is_empty()) | ||
| .map(|w| w.to_string()) | ||
| .collect() | ||
| }; | ||
| let title_tokens = tokenize(title_lc); | ||
| let url_tokens = tokenize(url_lc); | ||
| for t in title_tokens.iter().chain(url_tokens.iter()) { | ||
| let tw = t.trim_matches('-'); | ||
| if ADULT_TOKENS.contains(&tw) { | ||
|
Comment on lines
+1096
to
+1106
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win Split title and URL text at whitespace and hyphens. At Line 1097, the tokenizer preserves spaces and hyphens. A title such as The hard-drop path can therefore return explicit results for benign queries. Normalize separators before token matching and add regression cases for spaced and hyphenated markers. 🤖 Prompt for AI Agents |
||
| return true; | ||
| } | ||
| } | ||
| // Phrase markers (multi-word, lowercased) present in title or url. | ||
| const ADULT_PHRASES: &[&str] = &[ | ||
| "moms teach sex", "mom teaches sex", "mother son", "daughter father", | ||
| "incest porn", "family sex", "step sister", "step brother", "lesbian porn", | ||
| "gay porn", "teen porn", "amateur porn", "anal sex", "adult video", | ||
| "adult film", "adult movie", "webcam model", "only fans", "naked girls", | ||
| "naked women", "hot sex", "free porn", | ||
| ]; | ||
| let hay = format!("{} {}", title_lc, url_lc); | ||
| for p in ADULT_PHRASES { | ||
| if hay.contains(p) { | ||
| return true; | ||
| } | ||
| } | ||
| false | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift
Both jobs always skip, so CI reports success without testing anything.
No step starts the gateway, and
ubuntu-latesthas nothing listening on port 4000. The module fixtures in both test files callpytest.skipwhen/healthis unreachable, so every test skips and both jobs go green on every push and pull request. The PR objective states the schema tests are wired into CI, but these jobs give no regression signal.Start the stack in the job, or gate the jobs so a skip is visible. Two options:
docker compose up) beforepytest, and wait for/healthto return 200.workflow_dispatchandrepository_dispatchso the jobs do not advertise coverage on every pull request.🛠️ Sketch for option 1
🧰 Tools
🪛 zizmor (1.29.0)
[warning] 21-21: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[warning] 40-40: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[warning] 17-34: overly broad permissions (excessive-permissions): default permissions used due to no permissions: block
(excessive-permissions)
🤖 Prompt for AI Agents