Clarify create/download/update/publish decision table for shared indexes

Spell out explicitly, per run: check whether the shared index store
already has a published index; if so, fetch it regardless of access
level; a write-access user always continues to rebuild and publish
back to that same store, and this is precisely what creates it there
the first time the store is empty. A read-only user never rebuilds or
publishes anything, whether or not the store already had content.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Michał Kopeć 2026-07-20 16:22:55 +02:00
parent 946619de89
commit dc9f990bdd

View file

@ -27,9 +27,11 @@ Two refinements on top of that base design:
- **Shared, pre-built indexes.** `source.yaml` can declare *where the - **Shared, pre-built indexes.** `source.yaml` can declare *where the
already-built index lives* (a git repo, or a shared resource such as a already-built index lives* (a git repo, or a shared resource such as a
network path or another connector-reachable location), so a user doesn't network path or another connector-reachable location). Every run checks
have to build the index from scratch — they just fetch what's already that location: if it already has an index, fetch it; if it doesn't yet,
there. a write-access user's run is what creates it there for the first time.
Either way, a read-only user just gets whatever's already there — they
never have to build the index from scratch themselves.
- **Read vs. write access, per user, per source.** Building/refreshing an - **Read vs. write access, per user, per source.** Building/refreshing an
index from the live connector is gated by a **local, per-user** setting index from the live connector is gated by a **local, per-user** setting
(`libs/<name>/source.local.yaml`, never committed) — read-only by (`libs/<name>/source.local.yaml`, never committed) — read-only by
@ -118,32 +120,47 @@ this user is an admin for this one source; anything else (the field is
**per connector-backed lib** — a user can be write-access for one source **per connector-backed lib** — a user can be write-access for one source
and read-only for another. and read-only for another.
### Step 3 — Fetch a published index, if one is configured ### Step 3 — Check the shared index store, and fetch it if it exists
If `source.yaml` has an `index:` block, fetch/pull the latest published If `source.yaml` has an `index:` block, check whether `index.location`
index from `index.location` (per `index.store`: `git pull`/clone for already has a published index (per `index.store`: a `git` remote with
`git`, a plain file copy for a filesystem/network `shared` path, or the commits/a reachable ref, or a filesystem/network/`shared` location with
matching connector tool for a `shared` location that needs one) and use it files already in it):
to refresh `libs/<name>/{index.md,entities/,graph/,log.md}`. Do this - **It exists** → fetch/pull it (`git pull`/clone for `git`, a plain file
**regardless of this user's access level** — reading the published index copy for a filesystem/network `shared` path, or the matching connector
never requires write access, and it's exactly what lets a read-only user tool for a `shared` location that needs one) and use it to refresh
skip building anything themselves. `libs/<name>/{index.md,entities/,graph/,log.md}`. Do this **regardless
of this user's access level** — reading the published index never
requires write access, and it's exactly what lets a read-only user skip
building anything themselves.
- **It's empty / nothing published yet** → there's nothing to fetch. Don't
treat this as an error; it's the normal first-time state before anyone
with write access has run this. Continue to Step 4 — whether that turns
into "create it" or "nothing to report" depends entirely on this user's
access level.
If no `index:` block is configured, there's nothing to fetch — the index If no `index:` block is configured at all, skip this check — the index (if
(if any exists yet) already lives directly in `libs/<name>/`, same as any exists yet) already lives directly in `libs/<name>/`, same as before.
before.
### Step 4 — Decide whether to build or refresh from the live connector ### Step 4 — Decide whether to build or refresh from the live connector
This is the one place access level actually changes behavior:
- **Read-only** (the common case, and the default for anyone who hasn't - **Read-only** (the common case, and the default for anyone who hasn't
set `access: write` locally): stop here. Report what the fetched/existing set `access: write` locally): stop here, regardless of what Step 3
index already covers. If nothing has ever been indexed for this source found. Never touch the live connector on a read-only user's behalf.
and this user is read-only, say so plainly — don't scan the live - If Step 3 fetched something (or one already lived in `libs/<name>/`
connector on their behalf. Suggest asking whoever administers this with no `index:` block): report what it covers.
source to run it, or setting `access: write` locally if this user is - If nothing exists anywhere yet (Step 3 found the shared store empty,
meant to be that admin. or there's no `index:` block and `libs/<name>/` is empty too): say so
- **Write access**: continue to Step 5 and actually build/refresh the plainly, and suggest asking whoever administers this source to run it,
index from the live connector `location`. or setting `access: write` locally if this user is meant to be that
admin.
- **Write access**: always continue to Step 5, whether Step 3 fetched an
existing index (refresh it) or found the store empty (build the very
first version from scratch) — the two cases are handled identically
from here on; Step 7 is what actually creates the remote copy either
way.
### Step 5 — Resolve the connector and enumerate/summarize documents ### Step 5 — Resolve the connector and enumerate/summarize documents
@ -215,11 +232,22 @@ If this user has `access: write` **and** `source.yaml` has an `index:`
block, push the refreshed `libs/<name>/{index.md,entities/,graph/,log.md}` block, push the refreshed `libs/<name>/{index.md,entities/,graph/,log.md}`
back out to `index.location` (`git push` for `store: git`, a file copy back out to `index.location` (`git push` for `store: git`, a file copy
back for a filesystem/network `store: shared` path, or the matching back for a filesystem/network `store: shared` path, or the matching
connector tool for a `shared` location that needs one) — so every other connector tool for a `shared` location that needs one) — **every single
user's next fetch (Step 3) picks up the update. If no `index:` block is run**, not just the first one, so every other user's next fetch (Step 3)
configured, there's nothing to publish; the refreshed files staying inside picks up the update. This is exactly how a shared index gets created in
this repo's own `libs/<name>/` (tracked by this repo's own git) *is* the the first place: if Step 3 found the store empty, this step's push is what
publish step, same as the original default behavior. populates it for the first time; there's no separate "initialize" action.
If no `index:` block is configured, there's nothing external to publish;
the refreshed files staying inside this repo's own `libs/<name>/` (tracked
by this repo's own git) *is* the publish step, same as the original
default behavior.
If this user is **read-only**, this step never runs — nothing is ever
pushed or copied to `index.location` (or, in the no-`index:`-block case,
nothing is even rebuilt in `libs/<name>/` to begin with). A read-only user
has, by construction, nothing of their own to save back — Step 4 already
stopped them before anything was built.
### Step 8 — Remind to review and sync ### Step 8 — Remind to review and sync