Skip to content

Commit a3447f2

Browse files
committed
feat(agent-challenge): complete NO_PHALA offline pipeline with weight push
Drive the dual-flag-off analysis+own_runner path under NO_PHALA through scores and authenticated raw-weight push, with unattested provenance on completion metadata and CRITICAL push logs. Attested gates stay untouched.
1 parent 9d75607 commit a3447f2

12 files changed

Lines changed: 1845 additions & 12 deletions

File tree

packages/challenges/agent-challenge/docs/no-phala-mode.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,39 @@ Via master proxy (if embedded):
121121

122122
The **attested** emit branch in `own_runner_backend._emit_job_result` is not
123123
modified when NO_PHALA is off.
124+
125+
126+
## Full offline pipeline (master host)
127+
128+
With `NO_PHALA=true` and both attestation flags **off**, submit uses the
129+
pre-Phala analysis chain (not Phala review CVMs):
130+
131+
```text
132+
submit → analysis_queued → AST + LLM review → analysis_allowed
133+
→ waiting_miner_env (until env confirm / PUT)
134+
→ tb_queued → tb_running (own_runner on host Docker)
135+
→ tb_completed → EvaluationJob.score
136+
→ get_weights → authenticated raw-weight push (when master_base_url set)
137+
```
138+
139+
Requirements on the master process:
140+
141+
| Need | Env / setting |
142+
|------|----------------|
143+
| Mode | `NO_PHALA=true` or `CHALLENGE_NO_PHALA=true` |
144+
| Attestation off | `CHALLENGE_PHALA_ATTESTATION_ENABLED=false`, `CHALLENGE_ATTESTED_REVIEW_ENABLED=false` |
145+
| Worker | `CHALLENGE_COMBINED_WORKER=true` **or** run `agent-challenge-worker` |
146+
| LLM review | gateway base URL + token (else `llm_standby`) |
147+
| Benchmark | Docker + own_runner task cache |
148+
| Weight push | `CHALLENGE_MASTER_BASE_URL` + shared token (optional loop) |
149+
150+
**embed.env note:** master entrypoint only forwards keys matching
151+
`CHALLENGE_` / `PHALA_` / … prefixes. Prefer `CHALLENGE_NO_PHALA=true` in
152+
`/var/lib/base/challenges/agent-challenge/embed.env` so the child sees it.
153+
154+
Unattested provenance is visible on:
155+
156+
- result envelopes (`attested:false`, `attestation_status:unattested`, `execution_mode:no_phala_host`)
157+
- `tb_completed` status-event metadata (same fields)
158+
- CRITICAL log on every raw-weight push while the mode is on
159+
- `/health``no_phala:true`, `attestation_mode:no_phala_host`

packages/challenges/agent-challenge/src/agent_challenge/api/app.py

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@
44

55
import functools
66

7+
from fastapi import FastAPI
8+
79
from ..core import models as _models # noqa: F401 - register SQLAlchemy models
810
from ..core.config import settings
911
from ..core.db import database
12+
from ..evaluation import raw_weight_push as raw_weight_push_module
1013
from ..evaluation.weights import get_weights
1114
from ..evaluation.worker import run_worker_loop
12-
from ..sdk.app_factory import WorkerMain, create_challenge_app
15+
from ..sdk.app_factory import BackgroundTaskFactory, WorkerMain, create_challenge_app
1316
from ..sdk.config import ChallengeSettings
17+
from ..sdk.db import Database
1418
from ..sdk.observability import configure_root_logging
1519
from .routes import router
1620

@@ -30,10 +34,53 @@ def build_worker_main(challenge_settings: ChallengeSettings) -> WorkerMain | Non
3034
return functools.partial(run_worker_loop, manage_database=False)
3135

3236

33-
app = create_challenge_app(
34-
settings=settings,
35-
database=database,
36-
public_router=router,
37-
get_weights_fn=get_weights,
38-
worker_main=build_worker_main(settings),
39-
)
37+
def create_app(
38+
*,
39+
challenge_settings: ChallengeSettings | None = None,
40+
db: Database | None = None,
41+
) -> FastAPI:
42+
"""Build the Agent Challenge FastAPI app (production and tests).
43+
44+
Wires the optional combined worker and the authenticated raw-weight push
45+
loop the same way Prism does: build the client when settings enable it,
46+
append a background task factory, stash the client on ``app.state``.
47+
"""
48+
49+
app_settings = challenge_settings if challenge_settings is not None else settings
50+
app_db = db if db is not None else database
51+
configure_root_logging(app_settings)
52+
53+
background_tasks: list[BackgroundTaskFactory] = []
54+
# Attribute access (not a bound import) so tests can monkeypatch the module.
55+
push_client = raw_weight_push_module.maybe_build_push_client_from_settings(
56+
settings=app_settings,
57+
database=app_db,
58+
get_weights_fn=get_weights,
59+
)
60+
if push_client is not None:
61+
interval = float(getattr(push_client, "push_interval_seconds", 30.0))
62+
63+
async def _run_raw_weight_push(app: FastAPI) -> None:
64+
client = getattr(app.state, "raw_weight_push_client", push_client)
65+
await raw_weight_push_module.run_raw_weight_push_loop(
66+
client,
67+
interval_seconds=interval,
68+
resilient=True,
69+
)
70+
71+
background_tasks.append(_run_raw_weight_push)
72+
73+
app = create_challenge_app(
74+
settings=app_settings,
75+
database=app_db,
76+
public_router=router,
77+
get_weights_fn=get_weights,
78+
worker_main=build_worker_main(app_settings),
79+
background_tasks=tuple(background_tasks),
80+
)
81+
if push_client is not None:
82+
app.state.raw_weight_push_client = push_client
83+
return app
84+
85+
86+
app = create_app()

packages/challenges/agent-challenge/src/agent_challenge/core/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
)
2020
from sqlalchemy.orm import Mapped, mapped_column, relationship
2121

22+
from agent_challenge.evaluation.raw_weight_push import RawWeightPushLedger as RawWeightPushLedger
2223
from agent_challenge.sdk.config import ChallengeSettings
2324

2425
from .db import Base

0 commit comments

Comments
 (0)