LearnNewsExamplesServices
Frontmatter
id16592
titleThe neo tenant entry collides with kbSync and duplicates it untyped
stateClosed
labels
bugaiarchitecture
assigneesneo-opus-vega
createdAtAug 6, 2026, 2:28 PM
updatedAtAug 6, 2026, 3:04 PM
githubUrlhttps://github.com/neomjs/neo/issues/16592
authorneo-opus-vega
commentsCount0
parentIssue16566
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtAug 6, 2026, 3:04 PM

The neo tenant entry collides with kbSync and duplicates it untyped

Closed Backlog/active-chunk-13 bugaiarchitecture
neo-opus-vega
neo-opus-vega commented on Aug 6, 2026, 2:28 PM

Context

neo-shared/neo is registered as a pull-mode tenant repo, and kbSync also ingests neo's content. Both stamp {tenantId: neo-shared, repoSlug: neo}configBase.mjs:439/:447 default the stamp to exactly that tuple — while producing different chunk populations: kbSync emits typed/structured chunks (type: src|adr, kind: method|class-config|module-context|class-properties) from 10 source extractors, the tenant path emits untyped raw-file chunks via RawRepoSource because no parserId is declared.

Same identity, different content, so each lane classifies the other's rows as stale. Live consequence 2026-08-06: 17,550 rows deleted and not re-embedded, then a tenant repo's 50 rows swept by an unrelated lane.

This is not a config accident. D#15605's N=1 partial graduation registered neo as a pull-mode tenant deliberately, as a "whole-tree/zero-code PMV", and its point 3 required an identity-classified reconciliation receipt proving "zero same-identity double representation." That receipt was never produced — the lane never once completed — and the failure it named is what arrived. Full account at the D#15605 acquisition-vs-extraction lane.

The Problem

The neo tenant entry has served its purpose and now only costs:

  • Identity collision with kbSync, unfixable by #16584's scoping (which separates repo slugs, not lanes sharing one).
  • A strictly worse duplicate. It re-ingests content kbSync already provides typed; raw-file chunks cannot serve query_documents({type}) or get_class_hierarchy.
  • ~24k blob fetches per fresh mirror. Measured at the provider: 24,834 repository clones on 2026-08-05 against a ~1k/day baseline, uniques falling to 78 because it was one cloner. #16557 owns that cost.

Meanwhile multi-tenant ingestion has only ever been exercised with one viable tenant repo (create-app), so per-repo scheduling, jitter, independent backoff, and per-repo checkpointing have no multi-repo witness.

The Architectural Reality

kb-config.yaml's own comment states the constraint this ticket must respect: "branchRef is per-repo and NOT inheritable: neo integrates on dev, create-app has only main … Copying a sibling's branchRef is [wrong]." Verified against the remotes for both additions:

repo visibility branches blobs at HEAD size
neomjs/devindex-opt-in public main only 4 3 KB
neomjs/devindex-opt-out public main only 3 1 KB

So both take branchRef: main and credentialRef: none. Combined they add ~7 tracked files, which keeps the full sweep cycle in seconds and cannot reproduce the blobless clone cost.

Sequencing, not reversal. Neo returns as an ingestion tenant once sources/parsers are declarable per tenant — then it uses our own extractors rather than raw-file fallback, which is the outcome the N=1 slice was reaching for. That lane is D#15605's; this ticket only removes the entry that cannot work until then.

The Fix

ai/deploy/kb-config.yaml, tenants.neo-shared.tenantRepos:

  • Remove the neo entry.
  • Add devindex-opt-in and devindex-opt-out, each credentialRef: none, branchRef: main.
  • Update the surrounding comment so the branchRef lesson still names live entries rather than a removed one.

No code changes.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
tenantRepos[neo] D#15605 N=1 slice Removed; returns via declared sources kbSync already owns neo's corpus, typed kb-config comment collision measured 2026-08-06
tenantRepos[devindex-opt-in] this ticket branchRef: main, credentialRef: none kb-config comment remote: main only, 4 blobs
tenantRepos[devindex-opt-out] this ticket branchRef: main, credentialRef: none kb-config comment remote: main only, 3 blobs

Decision Record impact

none. A tenant-registration change. It does not amend ADR authority; the role split it anticipates is still in divergence at D#15605.

Acceptance Criteria

  • neo is absent from tenantRepos; devindex-opt-in and devindex-opt-out are present with branchRef: main and credentialRef: none.
  • The bootstrap-contract spec that guards the tracked bytes through the production reader/normalizer passes with the new roster, both mounts still pinned.
  • (post-merge) Three repos resolve, each with an independent checkpoint; a cycle summary reports 3 repos rather than 2.
  • (post-merge) create-app mints a receipt, commits its checkpoint, and its rows survive the following kbSync — the first time both have been true.
  • (post-merge) No lane deletes another's rows: per-repoSlug counts are non-zero for all three after a full sweep plus one kbSync.
  • (post-merge) No clone spike — the combined tenant surface is ~7 files.

Out of Scope

  • Declaring sources/parsers for any tenant, and re-registering neo — D#15605's lane.
  • The 132.7 MB blobless neo mirror and its tenant-repo-sync-revisions.json entry. Both become inert; the mirror is arguably a useful cache for when neo returns. Deliberately not deleted in the same change that stops using them.
  • #16557's acquisition cost, #16591's boundary spec, #16577's zero-chunk disposition.

Known coverage regression this accepts

neo was the only tenant repo whose branchRef differed from its default_branch. After this change every entry is main-on-main, so the per-repo branchRef resolution path loses its only live witness — precisely the path whose "not inheritable" lesson the config comment records. Stated rather than discovered later; a future non-default-branch tenant restores it.

Related

  • D#15605 — the acquisition-vs-extraction lane, the N=1 slice's origin, and the overdue point-3 receipt.
  • Epic #16566 · #16584 / PR #16590 (scoping, which cannot separate same-stamp lanes) · #16587 / PR #16583 · #16557 (held) · D#12034.

Origin Session ID: 6004a4aa-2089-4b14-b73f-b58c08cf53d9

Retrieval Hint: query_raw_memories("neo tenant entry removed devindex tenant repos identity collision") · ai/deploy/kb-config.yaml

Authored by @neo-opus-vega (Claude Opus 5).

tobiu referenced in commit 1472811 - "The tenant roster drops neo and gains two external proof repos (#16592) (#16593) on Aug 6, 2026, 3:04 PM
tobiu closed this issue on Aug 6, 2026, 3:04 PM