302 lines
11 KiB
Markdown
302 lines
11 KiB
Markdown
# STRING PPI production wiring — Task 2 identity validation
|
|
|
|
Date: 2026-07-21
|
|
Authoritative target: `/home/xzq/5090/PlantAI-dev4090-7/PlantAI-dev`
|
|
Scope: job-local target identity input only; no resolver/preflight decision wiring.
|
|
|
|
## Boundaries
|
|
|
|
- Added a read-only job-local identity reader for `config.xlsx`.
|
|
- Added independent request fields `targetScientificName` and `ppiTargetTreeTaxonId`.
|
|
- Passed those fields to the backend and returned a separate `target_identity` object.
|
|
- Did not modify KaKs, Ortholog, PPI execution, legacy recommendation replacement, or STRING resolver preflight decisions.
|
|
|
|
## Discovery evidence
|
|
|
|
The required first CodeGraph query was attempted:
|
|
|
|
```bash
|
|
timeout 15s codegraph explore "PpiSpeciesResolutionRequest species-resolution API job config.xlsx Species_Code Species_Name Taxon_ID TaxID NCBI_TaxID targetScientificName ppiTargetTreeTaxonId"
|
|
```
|
|
|
|
Exit code: `124`; no output. Targeted `rg` and bounded source reads were used after recording the timeout.
|
|
|
|
## RED evidence
|
|
|
|
Initial identity suite:
|
|
|
|
```bash
|
|
ssh planai5090 'cd /home/xzq/5090/PlantAI-dev4090-7/PlantAI-dev && /home/xzq/miniconda3/envs/test4py311/bin/python -m pytest -q tests/unit/test_ppi_target_identity.py'
|
|
```
|
|
|
|
Exit code: `1`. Result: `6 failed in 1.78s`.
|
|
|
|
- Five tests failed because `resolve_ppi_target_identity` did not exist.
|
|
- The request-contract test failed because `PpiSpeciesResolutionRequest` had no `targetScientificName` field.
|
|
|
|
Additional backend propagation RED:
|
|
|
|
```bash
|
|
ssh planai5090 'cd /home/xzq/5090/PlantAI-dev4090-7/PlantAI-dev && /home/xzq/miniconda3/envs/test4py311/bin/python -m pytest -q tests/unit/test_ppi_target_identity.py::test_explicit_identity_reaches_backend_without_using_ppi_species'
|
|
```
|
|
|
|
Exit code: `1`. Result: `1 failed in 0.32s`; failure was `TypeError: resolve_ppi_species_resolution() got an unexpected keyword argument 'target_scientific_name'`.
|
|
|
|
## GREEN evidence
|
|
|
|
Focused Task 2 suite:
|
|
|
|
```bash
|
|
ssh planai5090 'cd /home/xzq/5090/PlantAI-dev4090-7/PlantAI-dev && /home/xzq/miniconda3/envs/test4py311/bin/python -m pytest -q tests/unit/test_ppi_target_identity.py'
|
|
```
|
|
|
|
Exit code: `0`. Result: `7 passed in 1.80s`.
|
|
|
|
### Review-blocker correction: scientific-name conflict
|
|
|
|
The first Gate 2 review found that an explicit scientific name could be mixed
|
|
with a different job scientific name and the job TaxID. Two negative tests were
|
|
added before changing production code:
|
|
|
|
```bash
|
|
ssh planai5090 'cd /home/xzq/5090/PlantAI-dev4090-7/PlantAI-dev && /home/xzq/miniconda3/envs/test4py311/bin/python -m pytest -q tests/unit/test_ppi_target_identity.py::test_explicit_scientific_name_conflict_never_mixes_with_job_taxon tests/unit/test_ppi_target_identity.py::test_species_resolution_api_surfaces_scientific_name_conflict'
|
|
```
|
|
|
|
RED exit code: `1`. Result: `2 failed in 1.31s`; both helper and API returned
|
|
`resolved` instead of `conflict`.
|
|
|
|
After adding only the normalized-name consistency check, the same command had
|
|
exit code `0`: `2 passed in 1.25s`. The full Task 2 identity suite then had exit
|
|
code `0`: `9 passed in 1.37s`.
|
|
|
|
The conflict response is `target_scientific_name_conflict` and deliberately
|
|
leaves both `scientific_name` and `tree_taxon_id` empty, preventing a mixed
|
|
name/TaxID identity from reaching later stages.
|
|
|
|
Syntax and related identity/API/snapshot regression:
|
|
|
|
```bash
|
|
ssh planai5090 'cd /home/xzq/5090/PlantAI-dev4090-7/PlantAI-dev && /home/xzq/miniconda3/envs/test4py311/bin/python -m py_compile apps/web/pipeline_backend.py apps/web/vue3/main.py tests/unit/test_ppi_target_identity.py && /home/xzq/miniconda3/envs/test4py311/bin/python -m pytest -q tests/unit/test_ppi_target_identity.py tests/unit/test_ppi_frontend_display_contract.py tests/unit/test_string_species_snapshot.py tests/unit/test_string_species_registry.py'
|
|
```
|
|
|
|
Exit code: `0`. Result: `46 passed in 13.67s`.
|
|
|
|
Existing backend preflight regression probe:
|
|
|
|
```bash
|
|
ssh planai5090 'cd /home/xzq/5090/PlantAI-dev4090-7/PlantAI-dev && /home/xzq/miniconda3/envs/test4py311/bin/python -m pytest -q tests/unit/test_pipeline_backend_execution_env.py -k "ppi_species_resolution or os_direct_ppi"'
|
|
```
|
|
|
|
Exit code: `1`. Result: `8 passed, 1 failed, 30 deselected`.
|
|
|
|
The sole failure is `test_os_direct_ppi_uses_complete_string_registry_without_ortholog`, which expects a top-level `selection_mode`. That field belongs to Task 3 resolver/preflight wiring and is intentionally absent after Task 2. It is not claimed as passing here and was not repaired out of scope.
|
|
|
|
## Identity contract verified
|
|
|
|
- `Species_Code=Sv` plus repeated `Setaria_viridis` / `Setaria viridis` rows yields one canonical `Setaria viridis` identity.
|
|
- `Taxon_ID`, `TaxID`, and `NCBI_TaxID` are accepted; within one row their priority is that order.
|
|
- Explicit tree TaxID has priority but a mismatch with the unique job TaxID returns `target_taxon_id_conflict`; no silent overwrite occurs.
|
|
- Bare `Sv` with no job or explicit identity returns `target_string_tree_unresolved`; no two-letter-code guess occurs.
|
|
- Existing curated `Os -> 39947` and `Ft -> 62330` compatibility identities remain available.
|
|
- `ppiSpecies` remains `auto` when explicit target identity fields are supplied; target tree identity is not placed in `ppiSpecies`.
|
|
|
|
## Changed files and hashes
|
|
|
|
```text
|
|
apps/web/pipeline_backend.py
|
|
1c94e33a061fdeba6cc3816968b4e722a03fd3a2886665f6e28d848e24003ccf
|
|
|
|
apps/web/vue3/main.py
|
|
f12cddaaeb0d3e39165884cf1603ef05a79a14ceb02da5e1629fe83fd4e4180f
|
|
|
|
tests/unit/test_ppi_target_identity.py
|
|
7282a78e0e8a384f1ea1ad2abc58464b7d204ddd27e65a8da6e46b11e5965bdc
|
|
```
|
|
|
|
## Gate 2
|
|
|
|
- Job scientific-name identity: PASS.
|
|
- Explicit scientific-name and target-tree-TaxID request channels: PASS.
|
|
- Supported TaxID columns and deterministic row priority: PASS.
|
|
- Explicit/job TaxID conflict is structured: PASS.
|
|
- Explicit/job normalized scientific-name conflict is structured at helper and API layers: PASS.
|
|
- Conflicting scientific name is never combined with the job TaxID: PASS.
|
|
- Bare unknown short code is not guessed: PASS.
|
|
- Os/Ft compatibility identity: PASS.
|
|
- Target identity remains separate from `ppiSpecies`: PASS.
|
|
- Task 2 focused and related non-resolver regressions: PASS.
|
|
- Task 3 `selection_mode` regression: NOT PASSED / out of Task 2 scope.
|
|
|
|
Task 2 Gate: **PASS for identity-input scope only**. This does not authorize or claim Task 3 resolver/preflight completion.
|
|
|
|
## Online Gate on port 9010
|
|
|
|
The target has no systemd unit or dedicated 9010 restart script. The observed
|
|
authoritative process-management pattern was:
|
|
|
|
- `start_celery_9000.sh` with externally supplied
|
|
`BBAV5_QUEUE_PREFIX=plantai_4090_9010` and
|
|
`BBAV5_REDIS_URL=redis://localhost:6379/11` for five workers;
|
|
- direct `nohup ... python -m uvicorn apps.web.vue3.main:app --port 9010`
|
|
for the Web process.
|
|
|
|
Before restart, the exact 9010 master PIDs were:
|
|
|
|
```text
|
|
Web 2391890
|
|
default 2391860
|
|
heavy 2391866
|
|
medium 2391873
|
|
light 2391880
|
|
rnaseq 2391891
|
|
launcher shell 2391849
|
|
```
|
|
|
|
All six service processes had cwd
|
|
`/home/xzq/5090/PlantAI-dev4090-7/PlantAI-dev`, queue prefix
|
|
`plantai_4090_9010`, and Redis URL `redis://localhost:6379/11`.
|
|
|
|
Only those exact PIDs were stopped:
|
|
|
|
```bash
|
|
kill -TERM 2391890 2391860 2391866 2391873 2391880 2391891 2391849
|
|
```
|
|
|
|
Workers were restarted with:
|
|
|
|
```bash
|
|
env BBAV5_PROJECT_ROOT=/home/xzq/5090/PlantAI-dev4090-7/PlantAI-dev \
|
|
PLANTAI_PROJECT_ROOT=/home/xzq/5090/PlantAI-dev4090-7/PlantAI-dev \
|
|
BBAV5_CONDA_BASE=/home/xzq/miniconda3 \
|
|
BBAV5_DEFAULT_ENV=test4py311 \
|
|
BBAV5_QUEUE_PREFIX=plantai_4090_9010 \
|
|
BBAV5_REDIS_URL=redis://localhost:6379/11 \
|
|
BBAV5_CELERY_LOG_DIR=logs/runtime_9010/celery \
|
|
BBAV5_RNASEQ_CONCURRENCY=2 \
|
|
bash ./start_celery_9000.sh
|
|
```
|
|
|
|
Web was restarted with:
|
|
|
|
```bash
|
|
nohup env BBAV5_PROJECT_ROOT=/home/xzq/5090/PlantAI-dev4090-7/PlantAI-dev \
|
|
PLANTAI_PROJECT_ROOT=/home/xzq/5090/PlantAI-dev4090-7/PlantAI-dev \
|
|
BBAV5_QUEUE_PREFIX=plantai_4090_9010 \
|
|
BBAV5_REDIS_URL=redis://localhost:6379/11 \
|
|
/home/xzq/miniconda3/envs/test4py311/bin/python -m uvicorn \
|
|
apps.web.vue3.main:app --host 0.0.0.0 --port 9010 \
|
|
> logs/runtime_9010/web.log 2>&1 < /dev/null &
|
|
```
|
|
|
|
The combined remote shell initially attempted to write `web.pid` before its
|
|
backgrounded command group had created `logs/runtime_9010`, producing one
|
|
`No such file or directory` message. Process inspection showed the Web process
|
|
was healthy at PID `2455555`; the temporary wrapper shell PID `2455480` was
|
|
terminated and `logs/runtime_9010/web.pid` was corrected to `2455555`. No second
|
|
Web process was started.
|
|
|
|
After restart, the master PIDs were:
|
|
|
|
```text
|
|
Web 2455555
|
|
default 2455521
|
|
heavy 2455528
|
|
medium 2455537
|
|
light 2455544
|
|
rnaseq 2455556
|
|
```
|
|
|
|
Every PID changed. All six new processes have the authoritative target cwd,
|
|
queue prefix `plantai_4090_9010`, and Redis DB 11. The exact worker health check
|
|
was:
|
|
|
|
```bash
|
|
env BBAV5_PROJECT_ROOT=/home/xzq/5090/PlantAI-dev4090-7/PlantAI-dev \
|
|
PLANTAI_PROJECT_ROOT=/home/xzq/5090/PlantAI-dev4090-7/PlantAI-dev \
|
|
BBAV5_QUEUE_PREFIX=plantai_4090_9010 \
|
|
BBAV5_REDIS_URL=redis://localhost:6379/11 \
|
|
/home/xzq/miniconda3/envs/test4py311/bin/celery -A celery_app inspect ping \
|
|
-d plantai_4090_9010_default@xzq-Rack-Server,plantai_4090_9010_heavy@xzq-Rack-Server,plantai_4090_9010_medium@xzq-Rack-Server,plantai_4090_9010_light@xzq-Rack-Server,plantai_4090_9010_rnaseq@xzq-Rack-Server \
|
|
--timeout=10
|
|
```
|
|
|
|
Exit code: `0`; result: `5 nodes online`, all five returned `pong`. HTTP
|
|
`GET http://127.0.0.1:9010/docs` returned `200`.
|
|
|
|
### Live API evidence
|
|
|
|
Both requests used the real Sv job `job_1784552755238_b8762f` and endpoint
|
|
`POST http://127.0.0.1:9010/api/ppi/species-resolution`.
|
|
|
|
Exact request commands:
|
|
|
|
```bash
|
|
curl -sS -X POST http://127.0.0.1:9010/api/ppi/species-resolution \
|
|
-H "Content-Type: application/json" \
|
|
--data-binary '{"job_id":"job_1784552755238_b8762f","prefix":"Sv.HKL","ppiSpecies":"auto","targetSpecies":["Sv"],"referenceSpecies":[],"geneFamily":"HKL","requestedStages":["ppi"],"targetScientificName":"Setaria viridis","ppiTargetTreeTaxonId":"4556"}'
|
|
|
|
curl -sS -X POST http://127.0.0.1:9010/api/ppi/species-resolution \
|
|
-H "Content-Type: application/json" \
|
|
--data-binary '{"job_id":"job_1784552755238_b8762f","prefix":"Sv.HKL","ppiSpecies":"auto","targetSpecies":["Sv"],"referenceSpecies":[],"geneFamily":"HKL","requestedStages":["ppi"],"targetScientificName":"Oryza sativa","ppiTargetTreeTaxonId":"39947"}'
|
|
```
|
|
|
|
Consistent explicit identity:
|
|
|
|
```json
|
|
{
|
|
"targetScientificName": "Setaria viridis",
|
|
"ppiTargetTreeTaxonId": "4556"
|
|
}
|
|
```
|
|
|
|
Response summary:
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"requested_ppi_species": "auto",
|
|
"selection_mode": null,
|
|
"target_identity": {
|
|
"status": "resolved",
|
|
"scientific_name": "Setaria viridis",
|
|
"tree_taxon_id": "4556",
|
|
"identity_source": "explicit_taxon_id",
|
|
"config_scientific_name": "Setaria viridis",
|
|
"issue_code": ""
|
|
}
|
|
}
|
|
```
|
|
|
|
Conflicting explicit identity:
|
|
|
|
```json
|
|
{
|
|
"targetScientificName": "Oryza sativa",
|
|
"ppiTargetTreeTaxonId": "39947"
|
|
}
|
|
```
|
|
|
|
Response summary:
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"requested_ppi_species": "auto",
|
|
"selection_mode": null,
|
|
"target_identity": {
|
|
"status": "conflict",
|
|
"issue_code": "target_scientific_name_conflict",
|
|
"scientific_name": "",
|
|
"tree_taxon_id": "",
|
|
"explicit_scientific_name": "Oryza sativa",
|
|
"config_scientific_name": "Setaria viridis"
|
|
}
|
|
}
|
|
```
|
|
|
|
`selection_mode=null` is expected because Task 3 resolver/preflight wiring is
|
|
not part of this Gate. Port 9000 and port 19000 processes were not targeted or
|
|
restarted.
|
|
|
|
Online Task 2 Gate: **PASS**.
|