A waiting request says why it is not placed, on a worker
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Aptitud para principiantes
- 12/100
- Tipo de issue
- Nueva funcionalidad
- Claridad
- Bastante claro
- Estado de actividad
- Activo
- Stack tecnológico
- typescript
Línea de trabajo
Start in src/leasing/acquisition-planner.ts at the blocked return (around lines 222-224), which currently drops the capacity reason, then follow the coordinator's #defer path in src/leasing/lease-acquisition-coordinator.ts. The change touches the contract schema in src/contract/schemas.ts (which needs a protocol bump), the worker dispatcher, and the CLI and console, and the spec is part of feature #623, so confirm scope with maintainers first. Done means simlock list --requests shows a reason on queued requests only, and e2e/waiting-requests.test.ts passes with the new lines.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Part of #623.
Scope
On a single host (a worker), a request waiting in the queue says why it is not placed yet: in simlock list --requests, GET /v1/lease-requests, status.get waiting, and a "Why" row in the console's Waiting inspector. A worker's NO_CAPACITY answer names the capacity check that refused it, so #637 can show it on a gateway.
In short
Each time the daemon tries to place a waiting request, it keeps the reason the attempt stopped, in memory. A queued request shows the reason from its latest attempt. A starting request shows none: its stage already says the daemon is working on it. The reasons and their texts are feature #623 Shared values, rows "Waiting reason (worker)", "Reason text" and "NO_CAPACITY detail".
flowchart LR
A[Request arrives or queue wakes] --> P{Plan}
P -- grant / boot / create / evict --> S[starting]
P -- blocked --> R["Keep the reason on the waiter (new)"]
R --> Q[queued]
Q --> L["list.get requests: reason on the entry (new)"]
P -- blocked, noWait --> N["NO_CAPACITY with details.capacityReason (new)"]
Words used:
- Reason: the first check that stopped the request at its latest placement attempt, for example
platform-running-limit, printed "Full: running limit for iOS". - Capacity reason: one of the four capacity refusals (
device-limit,ram-budget,global-running-limit,platform-running-limit).
Before and after:
$ simlock list --requests
Request req_7: agent-b, ios iPhone 16, queued at 1, waiting 12s
Request req_9: agent-c, ios iPhone 16, queued at 2, waiting 3s
Request req_11: agent-d, android Pixel 8, starting, waiting 1s
$ simlock list --requests # after
Request req_7: agent-b, ios iPhone 16, queued at 1, waiting 12s — full: running limit for iOS
Request req_9: agent-c, ios iPhone 16, queued at 2, waiting 3s — behind an earlier request
Request req_11: agent-d, android Pixel 8, starting, waiting 1s
| Situation | Today | After |
|---|---|---|
| iOS running limit reached, nothing idle to shut down | queued at 1, waiting 12s |
... — full: running limit for iOS |
| Another request is ahead in the simulator/emulator line | queued at 2, ... |
... — behind an earlier request |
| Creating a device failed twice | queued at 1, ... |
... — creating a device failed twice |
| The warm pool is booting a device that fits | queued at 1, ... |
... — a matching device is starting |
| Physical: every match leased or absent | physical ..., queued at 1, ... |
... — every matching device is leased or absent |
| Being placed | starting, waiting 1s |
as today |
--no-wait at the RAM budget |
NO_CAPACITY, no details |
NO_CAPACITY, details.capacityReason: "ram-budget" |
If this goes wrong, a user would see a reason that is stale or wrong, or a reason on a request that is starting.
Technical spec
Facts
| # | Fact | Source |
|---|---|---|
| F1 | Only the head of the virtual line plans. Any other virtual waiter gets wait, or no-capacity under noWait, without asking the planner. |
src/leasing/lease-acquisition-coordinator.ts:891-907 |
| F2 | A queue wake drives the head of the virtual line and every pending physical waiter, nobody else. | src/leasing/lease-acquisition-coordinator.ts:1171-1181 |
| F3 | The planner waits, outside noWait, when the warm pool is booting or creating a fitting device for nobody. |
src/leasing/acquisition-planner.ts:107-116, :139-143 |
| F4 | A refused boot of a shut-down device with no idle device to evict is blocked; so is a boot whose claim is taken. |
src/leasing/acquisition-planner.ts:145-164 |
| F5 | A refused new device is blocked when there is no victim; at device-limit it first tries a managed victim; two failures block a provision that capacity allows. |
src/leasing/acquisition-planner.ts:166-187 |
| F6 | A taken eviction claim is blocked. The two eviction plans carry only a claim and a device, no reason. |
src/leasing/acquisition-planner.ts:67-76, :189-197 |
| F7 | blocked returns wait or no-capacity and drops the capacity reason it was given. |
src/leasing/acquisition-planner.ts:222-224 |
| F8 | A physical plan with no ready, present, free fit is blocked; a fit held for an older queued physical request is skipped. |
src/leasing/acquisition-planner.ts:128-137, :132; src/leasing/lease-acquisition-coordinator.ts:729-738 |
| F9 | The capacity refusal reasons are device-limit, ram-budget, global-running-limit, platform-running-limit. |
src/core/capacity/strategy.ts:30-34 |
| F10 | A blocked plan reaches #defer, which rejects a noWait waiter with NoCapacityError and enqueues any other. |
src/leasing/lease-acquisition-coordinator.ts:882-886, :1071-1078, :1239-1246 |
| F11 | After a first provisioning failure the waiter plans again at once; after a second it is enqueued without a plan, or a probe is declined with NoCapacityError. |
src/leasing/lease-acquisition-coordinator.ts:842-857 |
| F12 | A failed eviction (shutdown or delete threw) defers the waiter with no plan. | src/leasing/lease-acquisition-coordinator.ts:948-960, :978-984 |
| F13 | A physical waiter with no plan defers; a failed physical grant defers too. | src/leasing/lease-acquisition-coordinator.ts:718-721, :774-776 |
| F14 | A queued waiter whose spec matches a reclaiming device gets a reclaiming progress push; its plan is untouched. |
src/leasing/lease-acquisition-coordinator.ts:1080-1101 |
| F15 | NoCapacityError carries no fields. |
src/leasing/lease-acquisition-coordinator.ts:82-87 |
| F16 | Waiter state lives in memory only; a daemon start fails every request the previous process left open. | src/leasing/AGENTS.md "State and timers", "Rules" |
| F17 | waitingRequests() is the request book's waiting(queue.places()); places() gives a queuePosition only to a queued waiter, and the book maps that to stage queued, else starting. |
src/leasing/create-leasing.ts:280, src/leasing/wait-queue.ts:169-175, src/leasing/lease-request-book.ts:67-90, :308-313 |
| F18 | The gateway builds its own entries from the same book and its own WaitQueue. |
src/gateway/fleet-coordinator.ts:208-210 |
| F19 | waitingRequestSchema has no reason. It types list.get requests, status.get waiting, and a worker view's waiting. |
src/contract/schemas.ts:311-319, :1158; src/contract/operations.ts:123, :584 |
| F20 | The daemon parses each handler result through the output schema; an undeclared field is stripped. | src/contract/AGENTS.md "Rules" |
| F21 | The worker answers list.get requests and status.get waiting from queue.waitingRequests(). |
src/daemon/dispatcher.ts:380, :754 |
| F22 | GET /v1/lease-requests returns list.get requests as is; the console reads that route. |
src/http/app.ts:308-315, ui/src/state/waiting.ts:29 |
| F23 | NO_CAPACITY declares no details, and is not in CODES_WITH_DECLARED_DETAILS. |
src/contract/errors.ts:37, :148-175 |
| F24 | The socket sends details only from a DispatchError. HTTP puts them in the body only for a DispatchError whose code is in CODES_WITH_DECLARED_DETAILS. |
src/daemon/server.ts:843-853, src/http/errors.ts:154-170 |
| F25 | The worker dispatcher already turns a leasing error into a DispatchError with details: LEASE_ID_TAKEN with leaseId. |
src/daemon/dispatcher.ts:493-495 |
| F26 | POST /v1/lease-requests with noWait answers a refusal through errorResponse. |
src/http/app.ts:294-300 |
| F27 | fromWireError passes details through unchecked. |
src/contract/errors.ts:453-466 |
| F28 | The CLI parses the list with waitingRequestSchema and prints one line per request ending waiting <n>s. |
src/cli/index.ts:975-976, :987-1010 |
| F29 | The console's Waiting inspector shows cards for Waiting, Place, Stage, then facts Request, Created, Queue. A stage it does not know shows as its raw word. | ui/src/screens/waiting/index.tsx:108-142, ui/src/model/waiting.ts:104-124, ui/src/model/tones.ts:44, ui/src/model/waiting.test.ts:92 |
| F30 | The console's model/ imports contract types only. |
ui/AGENTS.md:5, :20 |
| F31 | Every contract shape change bumps the protocol by one in the same PR; the range is { min: 39, max: 39 }. |
docs/internal/agent-rules/toolchain.md:153-156, src/contract/AGENTS.md:58-60, src/contract/protocol.ts:13 |
| F32 | A replayed failed request answers its stored code only. | src/daemon/error-code.ts:90-94 |
| F34 | Cancelling a queued waiter rejects it and wakes nobody; so does enqueuing after a second provisioning failure. A queue timeout kicks the queue. | src/leasing/lease-acquisition-coordinator.ts:609-619, :842-857; src/leasing/create-leasing.ts:122-135 |
| F35 | The gateway lists a worker's own entries spread from its view, so every field the schema declares is kept. | src/gateway/dispatcher.ts:387-397 |
| F36 | The e2e test anchors each line at waiting \d+s$: single host at :46, :53; gateway at :91, :96, :98. Its limits are one iOS device, one running. |
e2e/waiting-requests.test.ts:13, :37-101 |
| F37 | Core's index re-exports capacity helpers but not CapacityRefusalReason, which only src/core/capacity/index.ts exports. |
src/core/index.ts:34-38, src/core/capacity/index.ts:21 |
| F33 | Docs that describe the line and the route today. | docs/CLI.md:1562-1580, docs/HTTP-API.md:1529-1561, docs/CONSOLE.md:289-313 |
What changes
-
The plan says why it is blocked.
blocked(F7) takes a reason and returns it onwaitandno-capacity. Each path gives:Path Reason Not the head of the virtual line (F1) behind-earlier-requestWarm pool booting a fit (F3) waiting-for-deviceBoot refused, no victim (F4) the refusal's capacity reason New device refused, no victim (F5) the refusal's capacity reason Victim found, its claim taken (F5, F6) the capacity reason that asked for the eviction Physical, only fits held for an older request (F8) behind-earlier-requestBoot claim already taken (F4) waiting-for-deviceTwo provisioning failures (F5) provisioning-failedPhysical, no fit free (F8) no-free-physicalThe
evict-runningandevict-managedplans also carry the capacity reason that asked for them (F6). The capacity reasons map one to one (F9). The mapping is aRecordkeyed by core'sCapacityRefusalReason, so the compiler fails when the two lists differ. -
The waiter keeps it. Every enqueue sets the waiter's reason from the plan that led to it. Each new plan replaces it. It is never written to
state.json(F16).- Enqueue after a second provisioning failure (F11):
provisioning-failed. - Failed eviction (F12): the capacity reason that asked for the eviction.
- Failed physical grant (F13):
no-free-physical. - A request whose match is being cleaned (F14) keeps the capacity reason its plan gave; the
reclaimingpush stays as today. - The head leaving without a wake (F34): cancelling a queued waiter, and enqueuing after a second provisioning failure, now wake the queue, so the new head plans again and replaces its
behind-earlier-request.
- Enqueue after a second provisioning failure (F11):
-
The listing shows it.
waitingRequests()addsreasonto eachqueuedentry that has one, never to astartingone (F17). The gateway's own entries get none (F18; #637 addsworkers). A gateway's list keeps thereasonon a worker's own entries (F35); the CLI prints them with the same suffix. -
NO_CAPACITYnames the capacity reason.NoCapacityErrorcarries the plan's reason. When it is a capacity reason, the worker dispatcher throwsDispatchError("NO_CAPACITY", message, { capacityReason }), as it does forLEASE_ID_TAKEN(F25). Otherwise no details, as today. So the socket sends it (F24), and HTTP's 503 body carriescapacityReason(F24, F26). A replay answers no details, as today (F32). -
CLI. A
queuedline with a reason ends—plus the reason text with only its first letter lower-cased. The text comes from feature #623 Shared values "Reason text"; the platform word is the request's (iOS,Android). -
Console. The inspector gains a "Why" fact after Queue, with the reason text, for an entry with a reason. No row otherwise. A reason the console does not know shows as its raw word, as a stage does (F29).
-
Two text tables, each checked. The CLI keeps its table in
src/cli, the console inui/src/model(F30). Each side has one test that its table covers every reason the contract's enum lists.
Modules touched
Searches: waitingRequestSchema, WaitingRequest, places(, blocked(, NoCapacityError, "NO_CAPACITY", CapacityRefusalReason, formatWaitingRequests, WaitingRow.
src/contract/schemas.ts,src/contract/errors.ts,src/contract/protocol.tssrc/core/index.ts(exportsCapacityRefusalReason)src/leasing/acquisition-planner.ts,src/leasing/lease-acquisition-coordinator.ts,src/leasing/lease-request-book.ts,src/leasing/wait-queue.ts,src/leasing/create-leasing.tssrc/daemon/dispatcher.tssrc/cli/index.tsui/src/model/waiting.ts,ui/src/screens/waiting/index.tsxe2e/waiting-requests.test.ts: its five line patterns (F36) gain the reason suffix, and the single-host test pins the limits below- Docs:
docs/CLI.md,docs/HTTP-API.md,docs/CONSOLE.md,docs/CLIENT.md; manualssrc/leasing/AGENTS.md,src/contract/AGENTS.md
flowchart LR
cli["CLI (changed)"] --> d["worker dispatcher (changed)"]
http[HTTP] --> d
ui["console Waiting (changed)"] --> http
d --> lease["leasing: coordinator, book (changed)"]
lease --> plan["planner (changed)"]
plan --> cap[capacity]
d --> contract["contract (changed)"]
sequenceDiagram
participant G as Gateway or client
participant D as Worker dispatcher
participant C as Coordinator
participant P as Planner
G->>D: lease.request noWait
D->>C: request
C->>P: plan
P-->>C: no-capacity, ram-budget
C-->>D: NoCapacityError(ram-budget)
D-->>G: NO_CAPACITY, details.capacityReason ram-budget
G->>D: list.get requests
D-->>G: [{ stage: queued, reason: platform-running-limit, ... }]
Contract and event changes
waitingRequestSchemagainsreason?: enumof the eight values in feature #623 Shared values "Waiting reason (worker)". A value outside the enum fails the parse, and so doesreasonon astartingentry.ErrorDetailsMap.NO_CAPACITYbecomes{ capacityReason?: enum of the four };NO_CAPACITYjoinsCODES_WITH_DECLARED_DETAILS.- This PR bumps the protocol by one,
minwith it (F31; feature #623 Shared values "NO_CAPACITY detail"). - Events: none.
Other code on the same state
Searches: readers of queue.pending(), queue.list(), .places() outside tests (4 hits in src/leasing, 5 in src/gateway); writers of waiter fields in lease-acquisition-coordinator.ts.
- Warm pool
waitingDemand(lease-acquisition-coordinator.ts:621-635) and#heldByOlder(:729-738): read spec and state, not the reason. No conflict. cancelPending(:609-619): rejects a queued waiter; it leaves the list (F17), and now wakes the queue (F34). A wake only plans the head and physical waiters under the lock, as every wake does.- The gateway (F18): shares the book and queue code. Its own entries carry no
reason; a worker's entries keep theirs (F35). - #637: adds
workersto the same schema and readsdetails.capacityReason. #637 depends on this task. - #629, #631, #635 each bump the protocol. The PR that merges second bumps again.
- #633: adds the wait p95 to the Waiting page. Other lines of the same screen; whichever merges second takes the base branch.
Failure modes
| Call | Outcome | What happens | Limit, counted from |
|---|---|---|---|
list.get requests |
ok | Each queued entry with its latest reason |
as today |
list.get requests |
client on another protocol | PROTOCOL_VERSION_UNSUPPORTED at hello, as today; existing hello tests cover it |
as today |
lease.request noWait |
capacity refusal | NO_CAPACITY with details.capacityReason |
none |
lease.request noWait |
other refusal (F1, F11, F8) | NO_CAPACITY, no details |
none |
lease.request noWait |
replayed by idempotency key | stored code, no details (F32) | none |
Console GET /v1/lease-requests |
unknown reason word | raw word in the Why row | none |
- Restart mid-step: the reason is in memory; the restart fails the request (F16). Nothing left behind; no test needed.
- Two callers at once: a listing reads the waiter's reason as the last plan left it. One thread; no torn read; no test needed.
Rules in play
architecture.md10: "A rule is enforced in exactly one place." The reason comes from the plan; each text table is checked against the contract's enum by a test; the capacity list is checked by the compiler.architecture.md16: "Policy is a pure function". The planner returns the reason; it stores nothing.architecture.md8: "The daemon owns all state; the CLI is a thin client." The CLI only prints the field.safety.md10: "Anything that arrives over the wire is a claim".reasonandcapacityReasonare closed enums in the contract.src/contract/AGENTS.md: "Every change to a contract shape bumps it by one in the same PR."testing.md6, 7: throughcreateLeasing, and the planner's own test for its many cases.documentation.md3: no repo path in what the CLI prints.
Tests
Seam: createLeasing through createTestEngine (src/leasing/testing.ts) and its waitingRequests(), which list.get requests returns (F21); model on src/leasing/create-leasing.test.ts:3757. The planner's cases in src/leasing/acquisition-planner.test.ts.
- Planner: each blocked path returns its reason: not tried by the planner; warm-pool boot
waiting-for-device; boot refusedram-budget,global-running-limit,platform-running-limit; provision refuseddevice-limit,ram-budget,global-running-limit,platform-running-limit; victim claim taken atdevice-limitand atplatform-running-limit, with the eviction plans carrying it; physical fits held only for an older requestbehind-earlier-request; boot claim takenwaiting-for-device; two failuresprovisioning-failed; physicalno-free-physical. Extend "waits or rejects when policy cannot reserve capacity" (acquisition-planner.test.ts:211). - The same reasons come back on
no-capacityundernoWait. - A queued request at the iOS running limit lists
reason: "platform-running-limit"; a second one behind it listsbehind-earlier-request; the stored request record has no reason. - The reason follows the latest attempt: when the head is granted, the request behind it becomes head and lists its own new reason, not
behind-earlier-request. - A request re-queued after its second provisioning failure lists
provisioning-failed, and the request behind it, now head, plans again and lists its own reason. - Cancelling the queued head makes the request behind it plan again and list its own reason, not
behind-earlier-request. - A request while the warm pool boots a fitting device lists
waiting-for-device. - A failed eviction lists the capacity reason that asked for it; a failed physical grant lists
no-free-physical; a request whose only match is reclaiming lists the planner's capacity reason. - A waiting physical request with every fit leased lists
no-free-physical(physical-leasing.test.ts:582). - A
startingrequest lists no reason: one being provisioned, and one held at its first plan. - A gateway's own queued entry lists no
reason: extendsrc/gateway/fleet-coordinator.test.ts:4309. A gateway'slist.get requestskeeps a worker's own entry'sreason: extendsrc/gateway/dispatcher.test.ts:1436. - Dispatcher: a
noWaitlease.requestrefused at the RAM budget, at the device limit and at the platform running limit rejectsNO_CAPACITYwithdetails.capacityReasonof each; one behind an earlier request rejectsNO_CAPACITYwith no details; a replay of the RAM-budget request by its idempotency key rejectsNO_CAPACITYwith no details. Model onsrc/daemon/dispatcher.test.ts:473. - HTTP:
POST /v1/lease-requestswithnoWaitat the running limit answers 503 withcapacityReasonin the error body (src/http/app.test.ts). - Contract:
waitingRequestSchemaaccepts each of the eight reasons on aqueuedentry, and refuses"bogus"and any reason on astartingentry;NO_CAPACITYis inCODES_WITH_DECLARED_DETAILS(src/contract/schemas.test.ts,errors.test.ts). - CLI: a queued request prints
— <text>for every reason,platform-running-limitonce for iOS and once for Android, only the first letter lower-cased; a queued request with no reason and a starting one print as today. Extendsrc/cli/index.test.ts:6284. - CLI and console tables: each side's table has a text for every reason the contract's enum lists (one test in
src/cli, one inui/src/model). - Console model: the chosen row's Why is the text for every reason, the raw word for an unknown one, and absent with no reason (
ui/src/model/waiting.test.ts). - Console screen: the inspector shows a Why fact after Queue with the text, and no Why fact for a starting request (
ui/src/screens/waiting/waiting.test.tsx:76). - E2E, single host (
e2e/waiting-requests.test.ts:37-55), limits{ ios: { maxDevices: 2, maxRunning: 1 }, maxRunning: 2 }, one lease held: agent-b's line ends— full: running limit for iOS, agent-c's— behind an earlier request. - E2E, gateway (
:57-101): the worker's local-b line ends— full: device limit, on the worker and on the gateway; the fleet line is unchanged.
Done when
- The tests above pass.
- On the fake driver, with
ios.maxDevices2,ios.maxRunning1, globalmaxRunning2 and one iOS lease held, a secondsimlock leasewaits;simlock list --requestsprints its line ending— full: running limit for iOS(e2e/waiting-requests.test.ts:37-55), and the console's Waiting inspector shows the same text under Why. - With the same limits, one iOS lease held and no request waiting,
lease.requestwithnoWait: trueover the socket is the head, and answersNO_CAPACITYwithdetails.capacityReason: "platform-running-limit". docs/CLI.md,docs/HTTP-API.md,docs/CONSOLE.mdanddocs/CLIENT.mddescribe the reason and the detail.
Out of scope
- A gateway's own entries and per-worker reasons (#637).
- A reason on a
startingrequest. - Keeping reasons across a restart, or in events.
- Waiting only behind same-platform requests (#387).
- The gateway's own
NO_CAPACITYcarrying a capacity reason.
Depends on
- #635
Written by an agent.
- Lenguaje dominante
- TypeScript
- Estrellas
- 19
- Forks
- 1
- Merge medio
- 7 h 21 min
- PR fusionados (30 d)
- 247
Preparar el entorno
Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de callstackincubator/simlock
-
bug:new
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
callstackincubator/simlock#673 ·
Los mantenedores suelen responder en 1 día
-
bug:needs-info
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
callstackincubator/simlock#657 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
callstackincubator/simlock#639 ·
Los mantenedores suelen responder en 1 día
-
bug:new
Dificultad 3/5 1-2 días Aptitud para principiantes 70/100
callstackincubator/simlock#672 ·
Los mantenedores suelen responder en 1 día
-
Flaky console lane: CLI auto-launch's fixed 5 s deadline expires while a daemon starts on a loaded runner (ENOENT daemon.sock)Posiblemente ocupada @V3RON la tomó hoy. Abiertobug:ready flaky-test
callstackincubator/simlock#663 · 1 comentario · 1 asignado ·
Los mantenedores suelen responder en 1 día
Todos los issues de callstackincubator/simlock
Issues similares
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 83/100
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
ranxianglei/billion-context#3583 ·
Los mantenedores suelen responder en 1 día
-
documentation v3
Dificultad 2/5 1-3 horas Aptitud para principiantes 73/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 73/100
anomalyco/opencode#56380 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
bug good first issue
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
NIAEFEUP/website-niaefeup-frontend#489 ·
Los mantenedores suelen responder en 2 días