mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
Snippet naming: content-derived on publish, frozen on explicit rename
This commit is contained in:
@@ -165,6 +165,20 @@ const active = useSnippetStore(selectActiveSnippet);
|
||||
> Rule: if you can compute it, do not store it. Add a new state field only for a
|
||||
> value that is _input_ the app receives, not output it derives.
|
||||
|
||||
### Editing buffers — the sanctioned duplication, and its sync rule
|
||||
|
||||
A text field with debounced auto-save (the metadata panel's Name/Comment, the editor
|
||||
buffer) legitimately mirrors a store fact into local component state: the local copy is
|
||||
the user's in-progress text, the store holds the saved value. This duplication carries an
|
||||
obligation the moment the store fact has **another writer** (publish's content-derived
|
||||
renaming, import, any store-side mutation): the component must **adopt** a store change it
|
||||
didn't make, or its debounced save will write the stale local copy back — silently undoing
|
||||
the other writer. The pattern (see `SnippetLibrary`'s `SnippetMeta`): track the last store
|
||||
value seen in a ref; when the store value changes, adopt it into local state **unless the
|
||||
user has diverged** (local ≠ previous store value) — in-progress typing always wins.
|
||||
Keying the component by entity id handles switching entities; this rule handles the same
|
||||
entity changing underneath.
|
||||
|
||||
---
|
||||
|
||||
## 3. Where State Lives: Central vs. Per-Feature Stores
|
||||
|
||||
@@ -464,7 +464,30 @@ user action — there is no separate coordinator module to call.
|
||||
|
||||
---
|
||||
|
||||
## 7. Where things live
|
||||
## 7. Snippet name provenance — the naming hierarchy
|
||||
|
||||
Snippet names (unlike dataset names) need no uniqueness; what they need is a rule for
|
||||
**who may rewrite them**. Each snippet carries `nameSource` (spec §09A): `'user'` names
|
||||
are frozen — set by an explicit rename (`SnippetStore.renameSnippet`) and never touched
|
||||
by the app again; `'auto'` names are app-picked and keep tracking the spec. On publish,
|
||||
an auto-named snippet is re-named from the now-published content in priority order: the
|
||||
spec's `title` (string, line array, or `{ text }` forms), else a mark + encodings
|
||||
description, else the existing name stands. The derivation dialect is deliberately the
|
||||
same one `generateChartName` uses for builder output, so manually authored and
|
||||
builder-built snippets read alike in the library.
|
||||
|
||||
Flow: `core/snippet.ts` (`deriveSnippetName`, `isAutoNamed`, `isDefaultSnippetName`) →
|
||||
`SnippetStore.publish` (the only rewrite site) / `renameSnippet` (the freeze site) →
|
||||
`SnippetLibrary`'s metadata panel (which must adopt a publish rename — arch 01 §2,
|
||||
editing buffers). Records predating `nameSource` have no provenance; `isAutoNamed`
|
||||
treats them as user-named unless the name is **provably** app-picked — the timestamp
|
||||
default shape, or identical to what `deriveSnippetName` returns for the record's own
|
||||
published spec. The conservative default is deliberate: rewriting a chosen name is worse
|
||||
than failing to track an auto one.
|
||||
|
||||
---
|
||||
|
||||
## 8. Where things live
|
||||
|
||||
| Concern | Location | Pure? | Tested |
|
||||
| ------------------------------------------------------------------------ | -------------------------------- | ------------------- | ----------- |
|
||||
@@ -474,6 +497,7 @@ user action — there is no separate coordinator module to call.
|
||||
| `snippetsReferencingDataset`, `datasetUsageCounts` (reverse-lookup scan) | `src/core/relationships.ts` | yes | unit |
|
||||
| `renameDatasetRefs` → updated count (rename propagation) | `src/app/stores/SnippetStore.ts` | no (mutates stores) | integration |
|
||||
| `dedupeIncomingNames` (datasets + custom themes) | `src/core/import-normalize.ts` | yes | unit |
|
||||
| `deriveSnippetName`, `isAutoNamed` (snippet name provenance) | `src/core/snippet.ts` | yes | unit |
|
||||
|
||||
The dividing line: anything that takes plain data and returns plain data is
|
||||
**core** and unit-tested in isolation; anything that reaches into a Zustand store
|
||||
|
||||
Reference in New Issue
Block a user