feat(8.0): visibility field (public/internal/system) on nouns + verbs
Adds a reserved, top-level `visibility` field (mirrors the subtype rollout): 'public' (default, surfaced) | 'internal' (developer app-internal — hidden from default find/count/stats, opt-in via includeInternal) | 'system' (Brainy plumbing, library-set only). Fixes a real leak: the VFS root entity counted in getNounCount() and appeared in find() (a fresh brain reported 1 entity). It is now visibility:'system' → excluded from every user-facing surface. Developers also get a first-class hidden-unless-asked tier (e.g. learned internals vs user-exposed data). - Reserved (RESERVED_ENTITY_FIELDS / RESERVED_RELATION_FIELDS) — spoof-proof from metadata. - Threaded through add/relate/update/transact; surfaced top-level on reads. - Default exclusion in counts (baseStorage), find()/related() (hard candidate filter via excludeVisibility — keeps topK/limit correct), and stats; includeInternal/includeSystem opt-ins. - VFS root marked 'system'. Tests: visibility.test.ts 17/17 (fresh-brain getNounCount()===0, internal hidden + opt-in, verb symmetry, top-level surfacing, metadata-spoof rejection). Unit 1431 green; count-synchronization integration now passes (off-by-one fixed).
This commit is contained in:
parent
0ca0e5c6cc
commit
f4dea80176
10 changed files with 777 additions and 41 deletions
|
|
@ -261,6 +261,7 @@ never appear inside a `metadata` bag:
|
|||
|---|---|---|
|
||||
| `noun` | `verb` | the `type` param of `add()` / `relate()` |
|
||||
| `subtype` | `subtype` | the `subtype` param |
|
||||
| `visibility` | `visibility` | the `visibility` param (`'public'` \| `'internal'`) |
|
||||
| `confidence` | `confidence` | the `confidence` param |
|
||||
| `weight` | `weight` | the `weight` param |
|
||||
| `service` | `service` | the `service` param (fixed at create time) |
|
||||
|
|
@ -300,6 +301,54 @@ entity.confidence // 0.95 — top level
|
|||
entity.metadata // { customer: 'acme', total: 129.5 }
|
||||
```
|
||||
|
||||
### Visibility — `public` / `internal` / `system`
|
||||
|
||||
`visibility` is a reserved tier that controls whether an entity or relationship
|
||||
surfaces on Brainy's **default** user-facing reads. The absence of the field is
|
||||
exactly equivalent to `'public'`.
|
||||
|
||||
| Tier | Counted in `getNounCount()` / `stats()`? | Returned by default `find()` / `related()`? | Opt-in |
|
||||
|---|---|---|---|
|
||||
| `'public'` (default, or field absent) | yes | yes | — |
|
||||
| `'internal'` | no | no | `find({ includeInternal: true })` / `related({ includeInternal: true })` |
|
||||
| `'system'` | no | no | `find({ includeSystem: true })` / `related({ includeSystem: true })` |
|
||||
|
||||
- **`'public'`** — normal data. Counted and returned everywhere. Stored lean:
|
||||
the field is omitted on disk for public records, so existing data needs no
|
||||
migration.
|
||||
- **`'internal'`** — your app's own bookkeeping (audit trails, derived caches,
|
||||
scratch entities) that should not pollute default queries, counts, or
|
||||
`stats()`, yet must stay retrievable on demand. Set it via the `visibility`
|
||||
param; read it back with the `includeInternal` opt-in.
|
||||
- **`'system'`** — Brainy's own plumbing (for example the Virtual File System
|
||||
root entity). Hidden everywhere by default — even when `includeInternal` is
|
||||
set — and surfaced only with the explicit `includeSystem` opt-in. The
|
||||
`'system'` tier is **not** part of the public `add()` / `relate()` param type
|
||||
(`'public' | 'internal'`); only internal Brainy code assigns it.
|
||||
|
||||
The opt-ins are applied as a **hard candidate filter** — hidden entities are
|
||||
removed before `limit` / `offset` are applied, so a default `find({ limit: 10 })`
|
||||
always returns ten *visible* results when that many exist, never a short page.
|
||||
|
||||
```typescript
|
||||
// App-internal scratch entity: present, retrievable, but out of the way.
|
||||
await brain.add({ type: 'task', data: 'reindex job', visibility: 'internal' })
|
||||
|
||||
await brain.getNounCount() // unchanged — internal not counted
|
||||
await brain.find({ type: 'task' }) // [] — hidden by default
|
||||
await brain.find({ type: 'task', includeInternal: true }) // includes it
|
||||
|
||||
// A brand-new brain reports zero user entities even though the VFS root exists:
|
||||
const fresh = new Brainy()
|
||||
await fresh.init()
|
||||
await fresh.getNounCount() // 0 — the root is visibility:'system'
|
||||
```
|
||||
|
||||
> **Note (8.0):** the structural `Contains` edges the VFS creates between
|
||||
> directories and files are left at the default (`public`) visibility for now —
|
||||
> only the VFS *root entity* is `'system'`. Marking those edges system requires
|
||||
> companion changes to VFS traversal and is out of scope for this change.
|
||||
|
||||
## What is not guaranteed
|
||||
|
||||
Stated plainly, so nothing surprises you in production:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue