---
id: 12052
title: 'Day0Tutorial Milestone 6: rewrite to first-class pull mode'
state: CLOSED
labels:
  - documentation
  - ai
assignees:
  - neo-opus-ada
createdAt: '2026-05-26T22:21:30Z'
updatedAt: '2026-05-26T22:58:22Z'
githubUrl: 'https://github.com/neomjs/neo/issues/12052'
author: neo-opus-ada
commentsCount: 0
parentIssue: null
subIssues: []
subIssuesCompleted: 0
subIssuesTotal: 0
blockedBy: []
blocking: []
closedAt: '2026-05-26T22:58:22Z'
---
# Day0Tutorial Milestone 6: rewrite to first-class pull mode

## Context

The Day-0 Cloud Deployment Tutorial's [Milestone 6 — Optional Clone / Server-Side Source](https://github.com/neomjs/neo/blob/dev/learn/agentos/cloud-deployment/Day0Tutorial.md#milestone-6---optional-clone--server-side-source) reads:

> Server-side clone is not part of the MVP push path. If the deployment receives only `{repo, ref, sha}` metadata and must fetch content itself, stop and route to [#11731](https://github.com/neomjs/neo/issues/11731). That path needs a credential-storage and clone-trust contract before implementation.

This framing is **materially stale** as of 2026-05-27. Epic [#11731](https://github.com/neomjs/neo/issues/11731)'s substrate has fully shipped. Pull mode is a first-class production option, not a future-deferred path.

Operators reading the Day-0 tutorial today see "deferred to #11731" and miss the entire shipped pull-mode surface — they either skip the milestone or route off the canonical path looking for non-existent design docs.

## The Problem

Three claims in Milestone 6 that are no longer accurate:

1. **"Server-side clone is not part of the MVP push path"** — accurate as written (push and pull are separate paths), but the phrasing implies pull mode is unavailable. It IS available; it's just additive to push, not part of it.

2. **"That path needs a credential-storage and clone-trust contract before implementation"** — the contract has shipped:
   - Credential boundary: [`TenantRepoAccessContract`](https://github.com/neomjs/neo/blob/dev/ai/services/knowledge-base/helpers/TenantRepoAccessContract.mjs) (#11787) defines the `cloneUrl` / `credentialRef` separation.
   - Clone primitive: [`GitMirror`](https://github.com/neomjs/neo/blob/dev/ai/services/knowledge-base/helpers/GitMirror.mjs) (#11788) resolves credentialRef at the `GIT_ASKPASS` subprocess boundary only; supports `env:`, `ssh:`, `file:` (#12032 / #12046) schemes.
   - Envelope builder: [`TenantRepoIngestEnvelopeBuilder`](https://github.com/neomjs/neo/blob/dev/ai/services/knowledge-base/helpers/TenantRepoIngestEnvelopeBuilder.mjs) (#11789).
   - Scheduler lane: `TenantRepoSyncService` (#11790) with the `tenant-repo-sync` orchestrator lane.
   - First-class additions since: [`RawRepoSource`](https://github.com/neomjs/neo/pull/12030), [`branchRef` schema](https://github.com/neomjs/neo/pull/12045), [Tier-1 `tenantRepoMirrorRoot` fallback](https://github.com/neomjs/neo/pull/12050).

3. **The expected-result placeholders** (`server-side clone: deferred to #11731` or `operator-owned Source registered intentionally`) don't reflect the actual shipped path. An operator reading the tutorial should see a concrete pull-mode setup recipe, not a deferred-status marker.

## The Architectural Reality

- [`learn/agentos/cloud-deployment/Day0Tutorial.md:567-588`](https://github.com/neomjs/neo/blob/dev/learn/agentos/cloud-deployment/Day0Tutorial.md#L567-L588) — Milestone 6 body.
- [`learn/agentos/cloud-deployment/TenantIngestionModel.md`](https://github.com/neomjs/neo/blob/dev/learn/agentos/cloud-deployment/TenantIngestionModel.md) — canonical operator-facing push + pull semantics. Already documents the pull-mode surface.
- [`learn/agentos/cloud-deployment/HookWiring.md`](https://github.com/neomjs/neo/blob/dev/learn/agentos/cloud-deployment/HookWiring.md) — push surfaces (`ai:kb-push-client`, `ingest_source_files`, `ai:ingest-tenant`); doesn't cover pull because pull doesn't have a hook surface — orchestrator-owned.
- [`learn/agentos/cloud-deployment/CustomSources.md`](https://github.com/neomjs/neo/blob/dev/learn/agentos/cloud-deployment/CustomSources.md) — `Source.extract` contract + `SourceRegistry` registration (still the right link for the full-corpus-build path).

## The Fix

Rewrite Milestone 6 to:

1. **Reframe**: "Optional Pull Mode / Server-Side Tenant Repo Sync" (push remains primary; pull is additive for tenants who want orchestrator-owned ingestion cadence rather than git-hook-driven publish).
2. **Concrete pull-mode setup recipe** (parallel to Milestone 3's push recipe):
   - Configure `tenantRepos[]` entry in the operator overlay.
   - Set `NEO_GITLAB_<SCOPE>_TOKEN` (or analog) for the credential indirection.
   - Trigger first sync via `node ai/scripts/maintenance/syncTenantRepos.mjs --repo-slug <slug>`.
   - Verify chunks via `ask_knowledge_base`.
3. **Remove the "deferred to #11731" framing** and the `server-side clone: deferred to #11731` expected-result block.
4. **Cross-link** to `TenantIngestionModel.md` for the operator decision model + `HookWiring.md` for the push-vs-pull selection guide.
5. **Preserve Custom Sources reference** at the bottom — the "operator owns full-corpus build" case is genuinely orthogonal to pull-mode-via-tenantRepos[] and still routes through `Source.extract`.

## Decision Record impact

`aligned-with ADR 0014` — documentation-only update. ADR 0014 already names tenant-repo-sync as a cloud-deployable lane; this PR just updates the tutorial to reflect the shipped state.

## Contract Ledger

| Target Surface | Source of Authority | Proposed Behavior | Fallback / Edge Case | Docs | Evidence |
| --- | --- | --- | --- | --- | --- |
| `Day0Tutorial.md` Milestone 6 heading | This ticket | Rename to "Optional Pull Mode / Server-Side Tenant Repo Sync"; remove "deferred to #11731" framing | Keep "Custom Sources" sub-reference for the full-corpus-build path (it's genuinely a different operator pattern) | The doc itself | Diff inspection — no remaining `deferred to #11731` in Milestone 6 body |
| `Day0Tutorial.md` Milestone 6 body | This ticket + `TenantIngestionModel.md` + `HookWiring.md` (already operator-canonical) | Concrete pull-mode setup recipe parallel to Milestone 3 (tenantRepos[] entry → credential → trigger → verify) | Skipping-Milestone-6 expected-result still allowed for push-only deployments; explicitly framed as "this milestone is optional if push covers your tenant content" | Cross-linked to `TenantIngestionModel.md` + `HookWiring.md` | Diff inspection — new section has the 4-step pull setup with file:line / command anchors |
| Expected-result placeholders (`server-side clone: deferred to #11731`) | This ticket | Replace with concrete result: `tenant repo synced + N chunks ingested + ask_knowledge_base returns refs` | Keep "skipped — push covers our content" as a valid expected-result for operators who don't need pull | The doc itself | Diff inspection — old placeholder text removed |
| Cross-links to sibling docs | `learn/agentos/cloud-deployment/TenantIngestionModel.md` + `learn/agentos/cloud-deployment/HookWiring.md` | Add explicit pointers from Milestone 6 body | Existing Related section retains all current links | Already canonical | New "Related" links inside Milestone 6 body |
| Non-overlap with `CustomSources.md` workflow | `CustomSources.md` (the full-corpus-build path remains the right surface for operator-owned source territories) | Preserve the existing pointer at the bottom of Milestone 6 for the genuinely-different "operator runs own full-corpus build" pattern | Both shapes can coexist in a single deployment (pull-mode for some tenants + Custom-Source for operator-owned content) | `CustomSources.md` | Diff inspection — Custom Sources link retained, framed correctly as orthogonal not redundant |

## Acceptance Criteria

- [ ] Milestone 6 heading reframed (no "Optional Clone / Server-Side Source"; new shape names pull-mode as a first-class option).
- [ ] No remaining text describing the path as "deferred to #11731" or "needs a credential-storage and clone-trust contract before implementation."
- [ ] Concrete pull-mode setup recipe present (parallel to Milestone 3's push recipe in shape).
- [ ] Cross-links to `TenantIngestionModel.md` + `HookWiring.md` added inside Milestone 6 body.
- [ ] Custom Sources reference preserved at the bottom for the orthogonal full-corpus-build path.
- [ ] Expected-result block describes the empirical pull-mode success state, not a deferred-status marker.
- [ ] No regression in surrounding Milestones (5 + 7 still flow naturally).

## Out of Scope

- Adding new operational features to pull-mode itself — the substrate is shipped; this is doc-only.
- Restructuring Day0Tutorial.md beyond Milestone 6 — Milestones 0-5 + 7 remain canonical.
- Rewriting `TenantIngestionModel.md` or `HookWiring.md` — they're already canonical and accurate; Milestone 6 just needs to point at them.
- Telemetry / health-payload changes — covered by [#11791](https://github.com/neomjs/neo/issues/11791) (operator docs + health/telemetry for tenant-repo ingestion).

## Avoided Traps

- **Deleting Milestone 6 entirely**: tempting since the "deferred" framing is stale, but Day0 numbering is referenced elsewhere; deleting a milestone reshuffles operator expectations. Reframe in place.
- **Folding pull-mode into Milestone 3 (push)**: would compress the push-vs-pull selection conversation. Keeping them in separate milestones preserves the operator decision-axis.

## Related

- Parent: [#11791](https://github.com/neomjs/neo/issues/11791) (operator docs + health/telemetry umbrella for tenant-repo ingestion). This Day-0 update is a focused sub-piece.
- Substrate that shipped (motivating the rewrite): [#11731](https://github.com/neomjs/neo/issues/11731) Epic + [#11787](https://github.com/neomjs/neo/issues/11787), [#11788](https://github.com/neomjs/neo/issues/11788), [#11789](https://github.com/neomjs/neo/issues/11789), [#11790](https://github.com/neomjs/neo/issues/11790) subs + [#12030](https://github.com/neomjs/neo/pull/12030), [#12045](https://github.com/neomjs/neo/pull/12045), [#12050](https://github.com/neomjs/neo/pull/12050) follow-ons.
- Empirical session anchor: first cloud-deployment exercise 2026-05-26 — pull-mode validated end-to-end in production-shape stack.

## Timeline

- 2026-05-26T22:21:31Z @neo-opus-ada assigned to @neo-opus-ada
- 2026-05-26T22:21:31Z @neo-opus-ada added the `documentation` label
- 2026-05-26T22:21:31Z @neo-opus-ada added the `ai` label
- 2026-05-26T22:23:27Z @neo-opus-ada cross-referenced by PR #12053
- 2026-05-26T22:58:22Z @tobiu referenced in commit `1bfee42` - "docs(day0): rewrite Milestone 6 to first-class pull mode (#12052) (#12053)

The previous "Optional Clone / Server-Side Source" framing described
pull mode as "deferred to #11731" + "needs a credential-storage and
clone-trust contract before implementation." Both claims are materially
stale — #11731's substrate has shipped end-to-end: TenantRepoAccessContract
(#11787), GitMirror (#11788), envelope builder (#11789), scheduler lane
(#11790), RawRepoSource (#12030), branchRef schema (#12045), file:
credentialRef (#12046), Tier-1 mirrorRoot fallback (#12050).

Reframe + rewrite per Contract Ledger rows in the ticket:

- Heading: "Optional Pull Mode / Server-Side Tenant Repo Sync".
- Reframe push (Milestone 3) as primary + pull as additive alternative
  for orchestrator-cadence ingestion.
- Concrete pull-mode setup recipe parallel to Milestone 3: tenantRepos[]
  config snippet + credential env var + sync trigger + ask_knowledge_base
  verification.
- Failure-signatures table covering KB_GITMIRROR_CLONE_FAILED (git
  binary missing per #12036 + token scope), KB_TENANT_REPO_CREDENTIAL_REF_
  REQUIRED / KB_GITMIRROR_CREDENTIAL_REF_INVALID, KB_TENANT_REPO_MIRROR_
  ROOT_REQUIRED.
- Cross-links to TenantIngestionModel.md (decision model) +
  HookWiring.md (push-vs-pull selection).
- Custom Sources reference preserved + reframed as genuinely orthogonal
  (operator owns full-corpus build) — not a fallback for pull mode.
- Expected-result block lists three valid shapes (pull-configured /
  skipped-push-covers-it / operator-owned-Custom-Source).

Net: ~70 LOC added, ~20 removed. All ACs on #12052 satisfied; Contract
Ledger row coverage verified surface-by-surface.

Co-authored-by: tobiu <tobiasuhlig78@gmail.com>"
- 2026-05-26T22:58:23Z @tobiu closed this issue

