# Task 4 validation — numeric TaxID to real STRING network Date: 2026-07-21 Target: `planai5090:/home/xzq/5090/PlantAI-dev4090-7/PlantAI-dev` Gate result: **PASS** ## Read-only implementation review The reviewed Task 4 implementation keeps the execution TaxID separate from the local gene-ID normalization label. Numeric execution taxa must be members of the fixed STRING snapshot; legacy species codes remain compatible. The TaxID survives preflight, API request normalization, worker parameters, backend CLI construction, skill execution, and manifest generation. `skills/ppi/run.py::StringAPI` discovers the official stable API address, rejects untrusted redirects, maps inputs through `get_string_ids`, attributes rows by `queryIndex`, validates TaxID and full STRING identifiers, and submits only validated IDs to `network` with `add_nodes=0`. Network rows are checked for TaxID, submitted endpoints, score range, and threshold. No Task 5 scheduling or UI behavior was changed during this Gate. CodeGraph was unavailable on the real target (`codegraph: command not found`, exit 127), so the review used targeted source reads after recording the limitation. ## Regression evidence The first test command referenced a nonexistent `tests/unit/test_string_rate_gate.py` and exited before collection. The corrected focused command ran only files present in the repository: ```text tests/unit/test_ppi_numeric_taxon_task4.py tests/unit/test_ppi_id_resolution.py tests/unit/test_string_ppi_production_wiring_red.py tests/unit/test_ppi_string_policy.py 43 passed in 13.90s ``` ## Official identifier discovery Initial official `get_string_ids` probes for TaxID 3708 were `FLC`, `FT`, `SOC1`, `AP1`, and `CO`. STRING mapped `FT` to `3708.D0QX04`. It also mapped `CO`, but the returned annotation described a magnesium transporter; this homonym was rejected as biologically unsuitable. `FLC`, `SOC1`, and `AP1` did not map. A second symbol-only probe (`LFY`, `AG`, `SVP`, `GI`, `LHY`, `TOC1`, `TFL1`, `FUL`, `SEP1`, `SPL3`, `SPL9`) returned zero mappings. The official species-specific STRING v12 aliases file was then downloaded from: ```text https://stringdb-downloads.org/download/protein.aliases.v12.0/3708.protein.aliases.v12.0.txt.gz ``` It records `3708.A0A078GRX0` with the product description `MADS-box protein SOC1`. The protein ID was not submitted directly to the network. The current `StringAPI.get_string_ids` first resolved the aliases-file token `A0A078GRX0`, together with `FT`, producing two validated mappings: | Query | STRING ID | TaxID | Preferred name | |---|---|---:|---| | `FT` | `3708.D0QX04` | 3708 | `FT` | | `A0A078GRX0` | `3708.A0A078GRX0` | 3708 | `BnaC04g50370D` | ## Real StringAPI Gate The Gate imported and executed the current `skills.ppi.run.StringAPI`; the HTTP recorder only observed the requests and did not bypass or replace its validation. | Step | Method and endpoint | HTTP | |---|---|---:| | version | `GET https://string-db.org/api/json/version` | 200 | | mapping | `POST https://version-12-0.string-db.org/api/json/get_string_ids` | 200 | | network | `POST https://version-12-0.string-db.org/api/json/network` | 200 | Version response: ```json { "string_version": "12.0", "stable_address": "https://version-12-0.string-db.org" } ``` Validated request summary: - TaxID: `3708` - Mapping input: `FT`, `A0A078GRX0` - Mapping result: `2/2` - Network input: `3708.D0QX04`, `3708.A0A078GRX0` - `required_score=200` - `network_type=functional` - `add_nodes=0` - `caller_identity=PlantAI` The real network request returned one validated edge: ```text 3708.A0A078GRX0 (BnaC04g50370D) -- score 0.467 --> 3708.D0QX04 (FT) ``` The response TaxID was 3708 and both endpoints were members of the submitted validated ID set. Therefore Task 4 passes the real STRING stable-v12 Gate. No service was restarted during the real-network Gate above, and no Task 5 work was performed. ## Deployment Gate on port 9010 Deployment Gate completed at `2026-07-21 06:04:42 CST`. Only the 9010 Web process and the five `plantai_4090_9010` worker parents were restarted after a directed `inspect active` reported all five workers empty. | Process | Old PID | New PID | Queue | |---|---:|---:|---| | Web 9010 | 2470234 | 2479563 | — | | default worker | 2470133 | 2479460 | `plantai_4090_9010.default` | | heavy worker | 2470139 | 2479470 | `plantai_4090_9010.heavy` | | medium worker | 2470146 | 2479477 | `plantai_4090_9010.medium` | | light worker | 2470155 | 2479484 | `plantai_4090_9010.light` | | rnaseq worker | 2470163 | 2479492 | `plantai_4090_9010.rnaseq` | The Web process and every worker reported cwd `/home/xzq/5090/PlantAI-dev4090-7/PlantAI-dev`. Every worker reported `BBAV5_QUEUE_PREFIX=plantai_4090_9010` and `BBAV5_REDIS_URL=redis://localhost:6379/11`. Redis DB11 returned `PONG`; a directed Celery ping returned `pong` from all five nodes; and `/api/celery/health` returned `ok=true`, the expected five queues, and all five project workers online. Port 19000 retained PID `2466042`; port 9000 had no listener before or after. Neither was signalled or restarted. The final socket check showed exactly one 9010 listener, PID `2479563`. ### Deployed request contract The live `GET /openapi.json` schema for `ExecuteRequest` exposes both `ppiSpecies` and `normalizationSpeciesLabel` as strings. A fresh deployed Pydantic model probe constructed: ```json { "ppiSpecies": "3708", "ppiSpecies_type": "str", "normalizationSpeciesLabel": "Bn" } ``` `model_dump()` retained both values exactly, so numeric-looking TaxID `3708` is not converted, truncated, or discarded by Pydantic. ### Fresh worker-environment import probe A separate fresh Python process used the same target cwd, test4py311 interpreter, queue prefix, and DB11 environment as the workers. It imported: ```text skills.ppi.run: /home/xzq/5090/PlantAI-dev4090-7/PlantAI-dev/skills/ppi/run.py gfa_core.mas.tools.stage_tools: /home/xzq/5090/PlantAI-dev4090-7/PlantAI-dev/gfa_core/mas/tools/stage_tools.py ``` `StringAPI.resolve_species_id("3708")` returned `"3708"`. A separate fresh process rejected `999999999` with `ValueError: STRING TaxID 999999999 is not in the fixed STRING snapshot registry` and exit code 1. No formal PPI task was submitted; end-to-end task submission remains reserved for Task 7. No Task 5 work was performed.