MotirBuilding in public
MOTIR · moooon
onMotir
You’re viewing a public project. Anyone can view it — no account needed. Sign in to submit, upvote, or comment on requests.View-only — you can’t edit work items
MOTIR-3759

(motir-core) The code-graph refresh costs ~35 minutes to re-derive a graph that measures 32 seconds — index ONCE per repo, and reach `codegraph sync`

To Do
Description

Repo · motir-core. One PR. Filed as the DEFERRAL card for the indexer's cost, which the engine-fairness story explicitly puts out of scope. It is related_to that story and blocked by nothing — the two are independent.

What is measured, and what is inferred

Measured, production, 2026-08-28 (job_run, read inside the Fly machine):

  • Six consecutive system.code-graph-refresh runs for moooon-B-V/motir-core: 2 058–2 116 s each, back to back 07:12→10:50.
  • Every run reports output.projectsIndexed: 2.
  • The same job for moooon-B-V/motir-ai took 226 s and for moooon-B-V/motir-meta 60 s, both also at projectsIndexed: 2.

Read in the code (origin/main):

  • lib/jobs/indexFleetSteps.ts:243for (const projectId of target.projectIds), i.e. one container per (repo × project), supervised sequentially.
  • The per-project dispatchInput differs in exactly ONE field, projectId. repoOwner, repoName, repoRef, defaultBranch, installationId and workspaceId are identical, so the same tree is cloned and parsed twice.
  • lib/jobs/definitions/codeGraphRefresh.ts states a refresh is a full whole-tree rebuild and has always been one.

Measured on a developer box, 2026-08-20, codegraph CLI 1.1.6 — a reading with a subject and a date, NOT a property of the fleet container, and to be re-taken before it is relied on:

operationwall
motir-core index --force (full)32.0 s
motir-core sync, 10 changed files0.7 s
motir-core sync, 2 481-file stale diff38.2 s

The two questions, in order

1 — Why is the parse duplicated per project? The graph is a property of the repository at a ref, and the ledger already treats it that way: one job_run per repo with one output.repoRef. If the per-project fan-out exists for tenancy of the PUBLISHED index rather than of the parse, then parse once and publish per project — which halves the work by construction and makes the sequential-vs-parallel question disappear. Settle this before optimising anything, because the answer may remove the second question.

2 — Where does the rest of the time go? 32 s of measured parse against ~2 100 s of production wall clock leaves ~98% unaccounted for. Instrument before fixing: the admission backoff, the boot/provision, the tarball fetch, and the poll-to-detect lag (indexPollWaitMs backs off to a 15 s cap, so detection alone costs up to 15 s per container). Do not assume which dominates.

Only THEN, incremental indexing

codegraph sync exists and is dramatically cheaper on a near-current graph. It has no caller: motir-ai's diff path GraphIndexPublisher.refresh was deleted on 2026-08-05 (MOTIR-2145) and the container runs a whole-tree build. Reaching it needs the prior .codegraph/codegraph.db carried or fetched as a base, and a "changed > X% of tree ⇒ full rebuild" threshold for the measured crossover. Worth doing for the fleet CPU it stops burning — not for latency, since per the numbers above the parse is a small share of the wall clock.

Acceptance criteria

  1. The card records whether the per-project fan-out is required for the PARSE or only for the PUBLISH, with the evidence read from the code that consumes the published index.
  2. If the parse is repo-shaped, the fan-out is restructured to parse once per (repo, ref) and publish per project, and a production run's duration is read back from job_run and quoted.
  3. A phase breakdown of one real refresh is recorded — admission, boot, fetch, parse, detect — each with the instrument that measured it.
  4. Any change to the fan-out is checked against codeGraphIndexAdmissionService's cap before it is made, and the card says what that cap permits.
  5. codegraph sync is either reached, with a stated full-rebuild threshold and a re-taken measurement on the CONTAINER rather than a developer box, or explicitly deferred to its own card with the reason.

Context refs

  • lib/jobs/indexFleetSteps.ts — the sequential per-project loop and the ledger contract.
  • lib/jobs/definitions/codeGraphRefresh.ts — the whole-tree-rebuild statement and its history.
  • lib/services/codeGraphIndexDispatchService.tsindexPollWaitMs, the admission backoff, MAX_POLL_ITERATIONS.
  • lib/services/codeGraphIndexAdmissionService.ts — the cap any parallelisation must respect.
  • MOTIR-3684system.code-graph-refresh failing ~32% on admission deferral; the same subsystem, a different symptom.
Status
To Do
Type
Feature