Files
PlantAI-dev/docs/validation/2026-07-21-string-ppi-task2-identity.md
2026-08-03 18:42:47 +08:00

11 KiB

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:

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:

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:

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:

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:

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:

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:

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

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:

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:

kill -TERM 2391890 2391860 2391866 2391873 2391880 2391891 2391849

Workers were restarted with:

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:

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:

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:

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:

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:

{
  "targetScientificName": "Setaria viridis",
  "ppiTargetTreeTaxonId": "4556"
}

Response summary:

{
  "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:

{
  "targetScientificName": "Oryza sativa",
  "ppiTargetTreeTaxonId": "39947"
}

Response summary:

{
  "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.