@niscorp/nisc 0.2.4 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -81,7 +81,7 @@ Pick per need; every piece works standalone. Nova is the only mandatory one for
81
81
  3. Reusable chrome (dialog frame, panel, drawer) is a fragment composed when an action is loaded (`with: [...]`), not a wrapper component. Modality is arrangement — an action loaded onto an overlay canvas with fragment chrome — never a `$.modalOpen` flag inside an action.
82
82
  4. Shell state is the truth. Routing (D5), if wired, is a data table mapping paths ↔ actions, synced by an adapter; Nova stays URL-agnostic. A **page** is not routing inside the app: it is a separate manifest at a path (`pages`), drawn and let go, and a path's parameters seed the canvas the page names — nothing else about a URL reaches an action.
83
83
 
84
- 4a. What a page says about itself is a node in a layout. Its title, its description and the card shown where a link to it is pasted are a `nova:head` node — props `title`, `description`, `image`, `kind`, `structured`, bound to the action's data like any other node's — which draws nothing and is written into the document's `<head>` by whoever draws the page (`nisc build`/`export`/`start`, moss's `renderDocument`); in the page the tab's title follows it. No hook builds a head, no script rewrites a drawn file, and `index.html` holds only what is the same on every page. Where a page lives is never in a layout: `site` in `nisc.config.ts` and the path say it. Whether it sits in the action's own layout or in chrome around it (a fragment, the frame) is arrangement, like everything else.
84
+ 4a. A page's `<head>` is a node in a layout. `nova:head` holds the elements a head holds — `nova:title`, `nova:meta`, `nova:link`, `nova:script` — and a child's props are that element's attributes, written as given and bound to the action's data like any other node's. Nothing in it is drawn on the screen; whoever draws the page writes it into the document's `<head>` (`nisc build`/`export`/`start`, moss's `renderDocument`), and in the page the head follows the screen. No hook builds a head and no script rewrites a drawn file. What runs or styles — a script a browser would execute, a stylesheet, `http-equiv` — is never in a layout: it goes in `index.html`, the app's own file, or in the kit component that needs it. A page's canonical address comes from `site` in `nisc.config.ts` and the path. Whether a head sits in the action's own layout or in chrome around it (a fragment, the frame) is arrangement, like everything else.
85
85
 
86
86
  **Data**
87
87
 
@@ -94,7 +94,7 @@ Pick per need; every piece works standalone. Nova is the only mandatory one for
94
94
 
95
95
  **Principals**
96
96
 
97
- 10. The charter is the app's policy document: role names → glob selections over the app's universes — `actions` (which action ids exist for a principal) and `data` (`table.verb` capabilities, compiled into the Vex `ScopePolicy`). The charter compiles; it never enforces and never shapes. Moss resolves it per principal and refuses to boot incoherent. Assignments (principal → roles) are app data beside it; row-level semantics the charter can't express are `behaviors`, compiled into the policy.
97
+ 10. The charter is the app's policy document: role names → glob selections over the app's universes — `actions` (which action ids exist for a principal) and `data` (`table.verb` capabilities, compiled into the Vex `ScopePolicy`). The charter compiles; it never enforces and never shapes. Moss resolves it per principal and refuses to boot incoherent. Assignments (principal → roles) are app data beside it; row-level semantics the charter can't express are `behaviors`, compiled into the policy. One role name is fixed: a request with no session, and a signed-in principal with no assignment, resolve to `public`, so every charter defines it — `public: []` where it grants nothing. Boot does not check for it; without it those requests fail (`Unknown role "public"`).
98
98
  10a. The `data` universe is the INTROSPECTED database, not your schema file: it holds the engine's own tables too — moss's `integrations` (integration key hashes), `integration_actions`, `moss_generation`, `sessions` (session token hashes, under moss's credential), the `strata_ledger`, the vex cache. A role granted a data wildcard (`*.read`) denies them explicitly (`data: { allow: ['*.read'], deny: [...] }`; denies do not inherit, so every role that grants the wildcard denies). A charter check resolves against the universe boot resolves against — the app's migrations and moss's run on a scratch database, then introspected — or it proves nothing about wildcards.
99
99
  11. Per-principal UI is existence or a served variant, never a conditional. An action a principal lacks does not exist in their shell (ring 1); a different shape of the same action is a served variant (ring 2). Layouts and components never branch on roles or capability data. Ring 1 does the deriving: a canvas's `initial` takes a **candidate list** and the first id the principal actually holds mounts — members boot their home, anonymous boots the login, and nobody configures which. An ungranted candidate simply isn't there.
100
100
  11a. Per-principal boot has two hooks, and they are twins. `inputs` derives boot **data** — merged over each canvas's static seed, read from action data downstream. `seeds` derives boot **instances** — which actions to push onto which canvases, computed from the session and its own reads over the session's wire, ring-1-filtered like every other mount. A composed surface (a home, an agent's column) is `seeds` plus a `list` canvas; hand-authoring the same arrangement names it twice. Branching chrome on `inputs` is a stopgap where a served variant doesn't exist yet.
@@ -115,7 +115,7 @@ Pick per need; every piece works standalone. Nova is the only mandatory one for
115
115
 
116
116
  17. No package — and no app, where it can help it — runs DDL outside a strata sequence. Tables change by APPENDING a migration to their owner's sequence; a migration that has run is history, checksummed in the ledger, and editing it makes every database that ran it refuse to boot. The first migration of a sequence may be the old `IF NOT EXISTS` DDL verbatim — split with `sqlSteps(ddl)`, never on every `;` — and that is how an existing database adopts. An app's own tables are its `<app>.app` sequence, migrated by its runtime before the seed (lyceum is the example).
117
117
  18. A grammar change is a migration. Changing a schema behind a document kind — nova's actions and layouts, Prism's config, an app kit's component props (`NiscApp.grammars`) — appends to that grammar's sequence: an empty marker for an addition (strict readers must still refuse the newer documents), document steps (a Prism config over ONE node; the grammar's embeddings find every node) for anything else. `pnpm check:grammars` refuses the change until it does, and checks every captured document still upgrades and parses. A grammar version is history — its migrations, and every corpus file captured at an earlier stamp. Its snapshot is its fingerprint: when the grammar did not change but what records it did (a validator describing the same schema differently, strata reading it differently), the current version is re-recorded with `pnpm strata:snapshot --rebaseline` (an app kit: its own snapshot script with `--rebaseline`) in a commit that changes nothing else, and only while the corpus passes — never edited by hand, never answered with a marker.
118
- 19. Stored and submitted documents carry the stamp they were written at and are upgraded where they are read. Ahead of the reader on any grammar is refused (`TOO_NEW`), never guessed at: the reader upgrades first — host before add-on, server before terminal.
118
+ 19. Stored and submitted documents carry the stamp they were written at and are upgraded where they are read. Ahead of the reader on any grammar the reader was given is refused (`TOO_NEW`), never guessed at: the reader upgrades first — host before add-on, server before terminal.
119
119
  20. An app's source records its grammars in `strata.lock.json`. When a grammar moves: `pnpm strata upgrade` writes the exact expected JSON and a report; edit what it lists; `pnpm strata verify` holds the edit to that JSON and only then moves the lock. Never edit the lock by hand, and never "fix" an edit toward a green verify by any route but the expected JSON. `pnpm check:sources` fails an app whose source is behind.
120
120
 
121
121
  ## A worked trio
package/CHANGELOG.md CHANGED
@@ -1,5 +1,136 @@
1
1
  # @niscorp/nisc
2
2
 
3
+ ## 0.3.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 6ab6f2b: `AGENTS.md` rule 10 says every charter defines a role named `public`. It is what a request with no session, and a signed-in principal with no assignment, resolve to; the name is fixed, and `public: []` grants nothing. Boot does not check for it: without it those requests fail with `Unknown role "public"`.
8
+
9
+ **What to change:** nothing, for a charter that has the role.
10
+
11
+ - bd3184d: An upgrade keeps a document's stamp entries for grammars the upgrader was not given.
12
+
13
+ `upgrade` handed back the upgrader's own stamp, and `upgradeStore` wrote it over the row's. A row stamped `{ "acme.forms": 0, "acme.prices": 1 }`, upgraded by code that was given `acme.forms` only, was written back stamped `{ "acme.forms": 1 }`: its record of `acme.prices` was gone. Code that has that grammar then read the row as never migrated and ran `acme.prices/1` over it a second time — a price already in cents, multiplied again.
14
+
15
+ The stamp now handed back, and written, is the upgrader's own plus the document's entries for any grammar it was not given, as they were. Nothing new is refused, and nothing else is written differently: for a document whose stamp names only the upgrader's grammars, `upgrade` returns `upgrader.stamp` itself, as before. `upgrader.stamp`, `behind`, the lock file and every ledger checksum are untouched.
16
+
17
+ `TOO_NEW` is, as it always was, about the grammars the code was given — a stamp entry for one it was not given is neither ahead nor behind. The README, DESIGN and rule 19 of `@niscorp/nisc`'s `AGENTS.md` said "on any grammar"; they now say "on any grammar the code was given".
18
+
19
+ **What to change:** nothing.
20
+
21
+ - Updated dependencies [2756aa7]
22
+ - Updated dependencies [0b5a7d6]
23
+ - Updated dependencies [4abbfcc]
24
+ - Updated dependencies [a02a031]
25
+ - Updated dependencies [d5c9d58]
26
+ - Updated dependencies [fa3f038]
27
+ - Updated dependencies [659b81e]
28
+ - Updated dependencies [3029c34]
29
+ - Updated dependencies [a7d4de4]
30
+ - Updated dependencies [f70d461]
31
+ - Updated dependencies [a7d4de4]
32
+ - Updated dependencies [979b3e3]
33
+ - Updated dependencies [63445cb]
34
+ - Updated dependencies [8973c15]
35
+ - Updated dependencies [ce21cf7]
36
+ - Updated dependencies [5923e38]
37
+ - Updated dependencies [2815107]
38
+ - Updated dependencies [885bc1e]
39
+ - Updated dependencies [f9f1b26]
40
+ - Updated dependencies [e3e0ff2]
41
+ - Updated dependencies [ed9d7f4]
42
+ - Updated dependencies [18182d7]
43
+ - Updated dependencies [bd3184d]
44
+ - Updated dependencies [bab7b2c]
45
+ - Updated dependencies [eef9cd9]
46
+ - Updated dependencies [e9ad028]
47
+ - Updated dependencies [1dfab19]
48
+ - Updated dependencies [008b5e8]
49
+ - @niscorp/cortex@0.1.3
50
+ - @niscorp/loom@0.2.2
51
+ - @niscorp/moss@0.3.2
52
+ - @niscorp/signal@0.1.3
53
+ - @niscorp/solid@0.1.2
54
+ - @niscorp/strata@0.1.3
55
+ - @niscorp/tide@0.1.4
56
+ - @niscorp/vex@0.2.2
57
+
58
+ ## 0.3.1
59
+
60
+ ### Patch Changes
61
+
62
+ - 353b3c3: `@niscorp/nova/examples` — the reference as data. `NOVA_EXAMPLES` is 42 examples, in six groups (`NOVA_EXAMPLE_GROUPS`): the layout grammar (12), actions at work (7), endpoints (5), composition with fragments (5), shells (8) and i18n (5).
63
+
64
+ An example is a small app, what is done to it, and what it must then say: `{ id, group, title, description, action | shell, fragments?, layouts?, replies?, fetches?, phrases?, phraseKeys?, stage?, presses, expected }`. `action` is one action alone on one canvas (an example of the layout grammar is an action with no triggers); `shell` is several actions on several canvases. `replies` and `fetches` say what its endpoints are answered, so an example comes to the same thing wherever it is run. `presses` is what is done: a press, something typed, or the host changing the language. `expected` is every piece of text the screen then holds (its text, and what stands in props at a prose key), the one action's data, which actions stand on each canvas, and what was sent to each URL.
65
+
66
+ Every id an example brings begins with its own, so a host can hold all of them in one shell. The examples a host puts on its stage name only the plain components every kit has (`Stack`, `Text`, `Button`, `Input`) and nova's two slots, with no prop about looks, so whoever shows them draws them with its own kit. An example with `stage: false` (the five on i18n) is shown as what it comes to. The package's tests run each one and hold it to its `expected`.
67
+
68
+ Not in it: the adapters' own seams (`slotWrapper`), the look of nova's default components, and the harvest functions of `@niscorp/nova/i18n`, which are called, not mounted.
69
+
70
+ **What to change:** nothing.
71
+
72
+ - 259a6f7: `@niscorp/prism/examples` — the reference as data. `PRISM_EXAMPLES` is 82 examples (`{ id, group, title, description, op?, source, config, expected }`): one for each of the 73 operators, named by the operator, then nine configs of several operators working together. `PRISM_EXAMPLE_GROUPS` names the groups they come in — the reference's own (Core, Arrays, Math, …), in its order. The package's tests evaluate each example against its `expected`, and fail when an operator has no example of its own or has two, so whatever shows them shows what the installed version does. `OP_KEYS`, the grammar's operator names in its own order, is now exported from the main entry. STYLE_GUIDE.md gains "Examples": a change to what a package does changes its examples in the same commit.
73
+ - Updated dependencies [06d1531]
74
+ - Updated dependencies [fe30458]
75
+ - Updated dependencies [353b3c3]
76
+ - Updated dependencies [7222c7d]
77
+ - Updated dependencies [c8982c2]
78
+ - Updated dependencies [1e6d55d]
79
+ - Updated dependencies [259a6f7]
80
+ - Updated dependencies [f801cc9]
81
+ - Updated dependencies [fc31d1d]
82
+ - Updated dependencies [18626f8]
83
+ - Updated dependencies [d2f0357]
84
+ - Updated dependencies [5c70059]
85
+ - @niscorp/cortex@0.1.2
86
+ - @niscorp/charter@0.1.2
87
+ - @niscorp/cli@0.3.1
88
+ - @niscorp/loom@0.2.1
89
+ - @niscorp/moss@0.3.1
90
+ - @niscorp/nova@0.2.1
91
+ - @niscorp/prism@0.2.1
92
+ - @niscorp/signal@0.1.2
93
+ - @niscorp/solid@0.1.1
94
+ - @niscorp/strata@0.1.2
95
+ - @niscorp/tide@0.1.3
96
+ - @niscorp/vex@0.2.1
97
+
98
+ ## 0.3.0
99
+
100
+ ### Minor Changes
101
+
102
+ - f1cec45: A Prism config that validates no longer names an op Prism does not have. `validate` accepted `{ card: { $fetch: … } }` and `{ $eval: "…" }`: the plain-object branch refused only the names of ops that exist, so any other `$` key passed as a template key. Such a config could be stored — an endpoint request, a vex mapping, a strata migration — and then failed every time it was evaluated (`E_NODE_SHAPE`, "Unsupported node shape").
103
+
104
+ A key that starts with `$` is now an op's name and nothing else. The template branch refuses every `$` key — the rule the evaluator already held — so `validate` reports it with the key and where it is (`card.$fetch: Not a Prism op. A key that starts with "$" names an op; data with such a key goes in $const.`), and `evaluate` and `compile` fail with `E_SCHEMA` before anything runs. An op's name used as a template key keeps its own message. `E_NODE_SHAPE` is left for a tree that never went through the schema: an IR handed to `execute`. Adding an op no longer takes a key away from templates.
105
+ - **prism** — the change, and a grammar narrowing: `nisc.prism` 2, a marker with no document step (a key that never evaluated has nothing to be rewritten to). `$` keys that are data are untouched: a `$const` payload, `$with` names, `$renameKeys` and `$fromEntries` keys. The JSON Schema's template key pattern is `^(?!\$)` instead of a list of every op.
106
+ - **nova, vex, moss, loom, cli, nisc** — no change of their own. They depend on prism and are released with it, so the set installs together; the configs they hand to prism (endpoint `request` and `response`, `$prism` bindings, vex mappings) are held to the same rule.
107
+ - **create-nisc** — the templates' sources are recorded at `nisc.prism` 2.
108
+
109
+ **What to change:** in a config with a `$`-prefixed key that is not a Prism op, remove the key — or put the object in `$const` if it is literal data. An app that keeps a `strata.lock.json` runs `pnpm strata upgrade`, then `pnpm strata verify`; there is nothing to edit unless it has such a config. Everything else: nothing.
110
+
111
+ BREAKING — approved by moccadroid, 2026-10-04: a config with a `$`-prefixed key that is not a Prism op no longer validates, compiles or evaluates — also where evaluation never reached the key (an untaken `$case` branch, a short-circuited `$or`, a `$map` body over an empty array), which used to work. A vex seed mapping with one fails when it is seeded, at boot, instead of on each replay. Code that matched `E_NODE_SHAPE` from `evaluate` gets `E_SCHEMA`. The `@niscorp` packages that depend on prism move with it, so an app moves them together (`@niscorp/nisc` 0.3.0).
112
+
113
+ ### Patch Changes
114
+
115
+ - de6d980: A fix for the last fix: `nova:head` is the document's `<head>`, and holds what a head holds. 0.1.4 gave it five props (`title`, `description`, `image`, `kind`, `structured`) and wrote tags from them, which closed a head to whatever nova had been taught: no `og:image:alt`, no `og:type` but two, no whole address inside structured data. That was wrong, and it is replaced, not extended. The maintainer withdrew 0.1.4's props on 2026-10-04; this ships as a patch on that decision.
116
+
117
+ **What to change** (only an app that used 0.1.4's props): a `nova:head` node no longer takes props. Write its children instead — `nova:title`, `nova:meta`, `nova:link`, `nova:script` — each with the element's attributes as its props. `{ title: X }` becomes `{ component: 'nova:title', children: X }`; `description` becomes `nova:meta` with `name: 'description'`; `image` and `kind` become `nova:meta` with `property: 'og:image'` and `property: 'og:type'`; `structured` becomes `nova:script` with `type: 'application/ld+json'` and `data`. `og:title` and `og:description` are no longer written from the title and description: say them if they are wanted. An address is written as given — a picture's is not made whole from `site`. Code that called `headOf`, `placeHead` or `createTitleKeeper`, or read `head` off `renderDocument`'s result or a route report, takes the new shapes below.
118
+ - **nova** — a head's children are the elements a head holds, named as HTML names them, and **a child's props are that element's attributes, written as given**: nova keeps no list of them, so any `name`, `property` or `rel` can be said. Nothing in a head is drawn on the screen and no name has to be registered. With more than one head on a screen they are read in the order the screen is drawn, and an element that says the same thing as an earlier one (the title, a `<meta>` of that name or property, the canonical address) takes its place; anything else stands beside its like. What runs or styles is refused, left out and named: a script a browser would execute (`nova:script` is a data block — a JSON `type`, never a `src`), a stylesheet, `http-equiv`, a handler attribute. `headOf(api)` returns `{ elements, actions, refused }`. In `@niscorp/nova/document`, `placeHead(html, elements, { site, path })` writes them — an element takes the place of the tag that said the same thing, where it stood; what it wrote is marked `data-nova-head`, and a tag that gave way is kept inert in a `<template data-nova-own>` — and `createHeadKeeper(document)` replaces `createTitleKeeper`: the whole head follows the screen in the page, and the document's own tags come back when the screen stops saying them. Removed: the five props, the `Head` and `HeadProps` types, `createTitleKeeper`.
119
+ - **cli** — `build`, `export` and `start` write each path's head from those elements. A head that holds what it may not fails the path, like any other check. `site` still gives every path its own canonical address and `og:url`; it no longer touches a picture's address.
120
+ - **moss** — `renderDocument` and `exportDocuments` do the same from the snapshot (`head` on the result is `{ elements, actions, refused }`; a refusal is logged and left out), and the terminal keeps the whole head off the wire.
121
+ - **create-nisc** — the two own-shell templates write their welcome screen's head this way.
122
+
123
+ **Where a script goes:** in the app's own `index.html`, which holds anything and from which every page is written, or in the kit component that needs it. A layout is data and does not carry one.
124
+
125
+ - Updated dependencies [de6d980]
126
+ - Updated dependencies [f1cec45]
127
+ - @niscorp/nova@0.2.0
128
+ - @niscorp/moss@0.3.0
129
+ - @niscorp/cli@0.3.0
130
+ - @niscorp/prism@0.2.0
131
+ - @niscorp/vex@0.2.0
132
+ - @niscorp/loom@0.2.0
133
+
3
134
  ## 0.2.4
4
135
 
5
136
  ### Patch Changes
package/STYLE_GUIDE.md CHANGED
@@ -114,6 +114,17 @@ This binds packages only. An app's prompt may be about its app — being fitted
114
114
 
115
115
  ---
116
116
 
117
+ ## Examples
118
+
119
+ A package's examples (`@niscorp/<package>/examples`) are its reference, as data: a document, what it is given, and what must come out. They ship with the package, and whatever shows them — nisc.dev, an agent reading `node_modules` — runs them with the version it has installed. That is what keeps a reference from falling behind the code: there is no second copy to forget.
120
+
121
+ - **A change to what a package does changes its examples in the same commit.** A new operator, component or field gets an example. A changed result changes that example's `expected`. The package's own tests hold both — every example answers what it says, and nothing in the grammar is left without one (prism: `test/examples.test.ts`).
122
+ - **`expected` is what the engine answers, read by a person.** Record it from a run, then read it. When a test goes red because an answer moved, find out why it moved before touching `expected` — the example may be the thing that is right.
123
+ - **An example is general**, as a prompt is ("Package prompts serve every app"): no app's names, data or domain.
124
+ - **Examples are data.** No function, no import of the engine: `{ id, group, title, description, … }` and the documents themselves. Whoever shows one supplies the code that runs it.
125
+
126
+ ---
127
+
117
128
  ## Unused Parameters
118
129
 
119
130
  Underscore prefix. Simple.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@niscorp/nisc",
3
- "version": "0.2.4",
3
+ "version": "0.3.2",
4
4
  "description": "The nisc platform as one known-compatible set: every @niscorp package, each pinned to the exact version it was released with.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -19,18 +19,18 @@
19
19
  "node": ">=22.12"
20
20
  },
21
21
  "dependencies": {
22
- "@niscorp/charter": "0.1.1",
23
- "@niscorp/cli": "0.2.3",
24
- "@niscorp/loom": "0.1.1",
25
- "@niscorp/cortex": "0.1.1",
26
- "@niscorp/moss": "0.2.4",
27
- "@niscorp/nova": "0.1.4",
28
- "@niscorp/signal": "0.1.1",
29
- "@niscorp/prism": "0.1.2",
30
- "@niscorp/strata": "0.1.1",
31
- "@niscorp/tide": "0.1.2",
32
- "@niscorp/vex": "0.1.1",
33
- "@niscorp/solid": "0.1.0"
22
+ "@niscorp/cli": "0.3.1",
23
+ "@niscorp/cortex": "0.1.3",
24
+ "@niscorp/loom": "0.2.2",
25
+ "@niscorp/charter": "0.1.2",
26
+ "@niscorp/moss": "0.3.2",
27
+ "@niscorp/prism": "0.2.1",
28
+ "@niscorp/nova": "0.2.1",
29
+ "@niscorp/signal": "0.1.3",
30
+ "@niscorp/solid": "0.1.2",
31
+ "@niscorp/strata": "0.1.3",
32
+ "@niscorp/tide": "0.1.4",
33
+ "@niscorp/vex": "0.2.2"
34
34
  },
35
35
  "peerDependencies": {
36
36
  "zod": "^4.2.0"