@kumbatio/energy-system 0.5.4 → 1.0.0
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/CHANGELOG.md +111 -0
- package/README.md +139 -2
- package/SPEC.md +439 -0
- package/api-surface.json +39 -1
- package/conformance.json +3176 -0
- package/dist/demand.d.ts +88 -0
- package/dist/demand.d.ts.map +1 -0
- package/dist/demand.js +166 -0
- package/dist/demand.js.map +1 -0
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +3 -32
- package/dist/engine.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/reconcile.d.ts +26 -0
- package/dist/reconcile.d.ts.map +1 -0
- package/dist/reconcile.js +75 -0
- package/dist/reconcile.js.map +1 -0
- package/dist/strategies.d.ts +26 -0
- package/dist/strategies.d.ts.map +1 -1
- package/dist/strategies.js +42 -0
- package/dist/strategies.js.map +1 -1
- package/package.json +17 -10
- package/spec/energy-state.schema.json +53 -0
- package/src/energy.css +77 -0
package/SPEC.md
ADDED
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
# The Energy Model — Specification
|
|
2
|
+
|
|
3
|
+
**Version 1 · normative · language-independent**
|
|
4
|
+
|
|
5
|
+
This document specifies the energy model: what an energy state is, how two of
|
|
6
|
+
them are ordered when they meet, and what each of the five levels means for the
|
|
7
|
+
behaviors built on top. `@kumbatio/energy-system` is the reference
|
|
8
|
+
implementation, not the definition. Anything that implements what is written
|
|
9
|
+
here — in Swift, Kotlin, Rust, Python, Go, or another JavaScript library — is an
|
|
10
|
+
implementation of the same model, and states produced by one may be read by
|
|
11
|
+
another.
|
|
12
|
+
|
|
13
|
+
There is a machine-readable half. [`conformance.json`](./conformance.json) ships
|
|
14
|
+
in this package and encodes every table and every decision below as vectors.
|
|
15
|
+
Load it, replay it, and you have a conformance suite without writing one. It is
|
|
16
|
+
generated from the built library, so the vectors and the reference
|
|
17
|
+
implementation cannot disagree.
|
|
18
|
+
|
|
19
|
+
Key words follow RFC 2119: **MUST**, **MUST NOT**, **SHOULD**, **MAY**.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 1. Why this exists as a spec at all
|
|
24
|
+
|
|
25
|
+
The claim the model makes is not "here is a nice API". It is that **capacity is
|
|
26
|
+
first-class application state** — as real as the current user or the current
|
|
27
|
+
document, and as deserving of a stable representation.
|
|
28
|
+
|
|
29
|
+
That claim only pays off if one person's energy state can be shared by
|
|
30
|
+
everything they use: a mail client, a writing tool, a coordination app, a phone.
|
|
31
|
+
Sharing state across processes and languages is an interchange problem, and
|
|
32
|
+
interchange needs a specification rather than a port. Five hand-written ports of
|
|
33
|
+
the same tables will drift within two releases, and on the day they disagree the
|
|
34
|
+
promise quietly becomes false.
|
|
35
|
+
|
|
36
|
+
So the portable artifact is this document plus the vectors. An implementation is
|
|
37
|
+
then a small amount of local code around a shared, checkable definition.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 2. Levels
|
|
42
|
+
|
|
43
|
+
The model has exactly **five** levels, and they are discrete.
|
|
44
|
+
|
|
45
|
+
| Value | Key | Label | Meaning |
|
|
46
|
+
| ----- | -------- | ------ | ---------------------------------------------------------- |
|
|
47
|
+
| `100` | `peak` | Peak | High capacity. Planning, complex decisions, creative work. |
|
|
48
|
+
| `75` | `active` | Active | Good capacity. Focused execution, problem-solving. |
|
|
49
|
+
| `50` | `steady` | Steady | Moderate capacity. Routine tasks, familiar work. |
|
|
50
|
+
| `25` | `low` | Low | Limited capacity. Simple tasks, review, light work. |
|
|
51
|
+
| `0` | `rest` | Rest | Depleted. Consumption only — reading, reflecting. |
|
|
52
|
+
|
|
53
|
+
An implementation **MUST** use exactly these five values and **MUST NOT** admit
|
|
54
|
+
intermediate ones. This is a design commitment, not an arbitrary limit: a
|
|
55
|
+
continuous slider asks for precision nobody has about their own state, and it
|
|
56
|
+
turns a one-second act into a judgement call at exactly the moment judgement is
|
|
57
|
+
expensive. Five is also few enough to cycle through with one key.
|
|
58
|
+
|
|
59
|
+
Each level carries a **cognitive profile** — `decisionCapacity`,
|
|
60
|
+
`focusDuration`, `taskComplexity`, `interruptionTolerance` — enumerated in the
|
|
61
|
+
vectors under `levels`. Implementations **MUST** reproduce these values;
|
|
62
|
+
consumers branch on them.
|
|
63
|
+
|
|
64
|
+
**Cycling** is `100 → 75 → 50 → 25 → 0 → 100`. Downward by default, because the
|
|
65
|
+
common act is admitting depletion, and the wrap gives one control both
|
|
66
|
+
directions. See `cycle` in the vectors.
|
|
67
|
+
|
|
68
|
+
### 2.1 What the levels are not
|
|
69
|
+
|
|
70
|
+
They are not a scale of worth, and an implementation **SHOULD NOT** present them
|
|
71
|
+
as a score, a streak, or something to optimise. Rest is a valid state to be in
|
|
72
|
+
and the interface **SHOULD** be usable there. An implementation **MUST NOT**
|
|
73
|
+
make Rest a degraded or punitive mode.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## 3. Energy state
|
|
78
|
+
|
|
79
|
+
The unit of interchange is an **energy state**: one producer's point-in-time
|
|
80
|
+
claim about a person's capacity. Its serialized form is specified by
|
|
81
|
+
[`spec/energy-state.schema.json`](./spec/energy-state.schema.json).
|
|
82
|
+
|
|
83
|
+
| Field | Type | Role |
|
|
84
|
+
| ----------- | --------------------------------- | -------------------------------------------- |
|
|
85
|
+
| `level` | `0 \| 25 \| 50 \| 75 \| 100` | The declared capacity. |
|
|
86
|
+
| `timestamp` | integer, epoch milliseconds | When it was produced. Primary ordering key. |
|
|
87
|
+
| `source` | `manual \| scheduled \| inferred` | How it was arrived at. |
|
|
88
|
+
| `revision` | non-negative safe integer | Sequence among states sharing one timestamp. |
|
|
89
|
+
| `origin` | non-empty string | Stable identity of the producer. |
|
|
90
|
+
|
|
91
|
+
A state **MUST** be immutable once produced. Implementations **SHOULD** enforce
|
|
92
|
+
this with whatever their language offers.
|
|
93
|
+
|
|
94
|
+
### 3.1 Source
|
|
95
|
+
|
|
96
|
+
`source` is not decoration; §4 gives it authority.
|
|
97
|
+
|
|
98
|
+
- `manual` — the person set it. **The default, and the trust anchor.**
|
|
99
|
+
- `scheduled` — a rule the person configured applied it (a calendar, a time of day).
|
|
100
|
+
- `inferred` — the system worked it out from behavior.
|
|
101
|
+
|
|
102
|
+
An implementation **MUST** support `manual`. Inference **MAY** be offered but
|
|
103
|
+
**MUST** be opt-in, and a system that infers **SHOULD** present the result as a
|
|
104
|
+
suggestion the person confirms rather than applying it silently. A model of
|
|
105
|
+
someone's capacity that overrides what they said about it recreates the loss of
|
|
106
|
+
control the model exists to answer.
|
|
107
|
+
|
|
108
|
+
### 3.2 The unproduced sentinel
|
|
109
|
+
|
|
110
|
+
An implementation needs a state before anyone has set one. That default **MUST**
|
|
111
|
+
be distinguishable from a real state, because "nobody has chosen yet" and
|
|
112
|
+
"someone chose Peak" are different facts and only the second should survive
|
|
113
|
+
reconciliation.
|
|
114
|
+
|
|
115
|
+
The sentinel is `timestamp = 0` together with `origin = "0-initial"`. Both sort
|
|
116
|
+
below any real value, so §4 replaces the default unconditionally.
|
|
117
|
+
|
|
118
|
+
Producing the sentinel **MUST NOT** require reading the clock or a random
|
|
119
|
+
source. This is not a micro-optimisation: constructing a state during a
|
|
120
|
+
server-side render otherwise bakes an unstable value into static output, which
|
|
121
|
+
some frameworks fail the build on outright.
|
|
122
|
+
|
|
123
|
+
### 3.3 Rejecting implausible states
|
|
124
|
+
|
|
125
|
+
An implementation that accepts states from outside itself **SHOULD** reject any
|
|
126
|
+
whose `timestamp` exceeds local time by more than a bounded skew budget. Without
|
|
127
|
+
it, one context with a badly-set clock wins every comparison until real time
|
|
128
|
+
catches up to its timestamp — which may be years.
|
|
129
|
+
|
|
130
|
+
The reference default is **5 minutes**. The budget **SHOULD** be configurable,
|
|
131
|
+
including "accept anything finite" for controlled environments.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 4. Reconciliation
|
|
136
|
+
|
|
137
|
+
> This is the section to get right. Everything else is a table.
|
|
138
|
+
|
|
139
|
+
Two states for the same person meet constantly: a second tab writes shared
|
|
140
|
+
storage, two windows each hold a producer, a sync layer returns what another
|
|
141
|
+
device recorded. Every path needs the same answer to _which of these is
|
|
142
|
+
current_, and the answer **MUST** be a deterministic function of the two states
|
|
143
|
+
alone. "Last write wins by arrival order" is not acceptable: it converges on
|
|
144
|
+
different values depending on timing, so two contexts disagree permanently.
|
|
145
|
+
|
|
146
|
+
Given a `candidate` and a `current`, the candidate replaces the current if and
|
|
147
|
+
only if the first differing key below favours it:
|
|
148
|
+
|
|
149
|
+
1. **`timestamp`** — greater wins.
|
|
150
|
+
2. **`revision`** — greater wins.
|
|
151
|
+
3. **`source`** — `manual` (3) > `scheduled` (2) > `inferred` (1).
|
|
152
|
+
4. **`origin`** — greater by lexicographic comparison of the string.
|
|
153
|
+
|
|
154
|
+
If all four are equal, the states are equal: the candidate **MUST NOT** replace
|
|
155
|
+
the current, and no change **MUST** be reported.
|
|
156
|
+
|
|
157
|
+
Key 4 is arbitrary and deliberately so. When two producers write the same
|
|
158
|
+
instant, the same revision, and the same class of source, there is no principled
|
|
159
|
+
winner — and an arbitrary rule every context computes _identically_ beats a coin
|
|
160
|
+
flip each context tosses separately. Convergence is the property that matters.
|
|
161
|
+
|
|
162
|
+
An implementation **MUST** additionally treat a `level` difference as a
|
|
163
|
+
tiebreaker below key 4 (greater wins). This is unreachable for conforming
|
|
164
|
+
producers, since it requires one `origin` to have produced two different states
|
|
165
|
+
with identical timestamps and revisions. It exists so a buggy producer causes a
|
|
166
|
+
wrong answer rather than an oscillation.
|
|
167
|
+
|
|
168
|
+
**Antisymmetry is required.** For any two states, both directions **MUST NOT**
|
|
169
|
+
report "preferred". Two contexts observing each other would otherwise swap
|
|
170
|
+
states forever. The vectors assert both directions of every pair for this
|
|
171
|
+
reason.
|
|
172
|
+
|
|
173
|
+
Reference: `isPreferredEnergyState`; vectors under `reconciliation`.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## 5. Adaptation strategies
|
|
178
|
+
|
|
179
|
+
A **strategy** is a pure total function from level to a configuration value. It
|
|
180
|
+
**MUST** be free of side effects, **MUST** be defined for all five levels, and
|
|
181
|
+
**MUST** return the same value for the same level every time.
|
|
182
|
+
|
|
183
|
+
The distinction that keeps the model honest is **strategies describe, runtimes
|
|
184
|
+
enforce**. A strategy says "at Steady, notifications batch every five minutes";
|
|
185
|
+
something else does the batching. Keeping the description pure is what makes it
|
|
186
|
+
portable, testable, and readable by a person deciding whether to trust it.
|
|
187
|
+
|
|
188
|
+
Seven strategies are specified. Their complete per-level tables are in the
|
|
189
|
+
vectors under `strategies`; they are not reproduced here, because a table
|
|
190
|
+
duplicated in prose is a table that will disagree with itself.
|
|
191
|
+
|
|
192
|
+
| Name | Governs |
|
|
193
|
+
| ------------------------- | ------------------------------------------------------------------ |
|
|
194
|
+
| `ui-visibility` | Which chrome is shown, its opacity, content width and font scale. |
|
|
195
|
+
| `notifications` | Channels, batching interval, and minimum priority. |
|
|
196
|
+
| `task-complexity` | Ceiling on surfaced task complexity; break cadence. |
|
|
197
|
+
| `interaction-forgiveness` | Undo window, destructive-action confirmation, autosave cadence. |
|
|
198
|
+
| `deferral` | Ordering of "not now" presets, and the one-tap default. |
|
|
199
|
+
| `autonomy` | What automation may do unattended (§7). |
|
|
200
|
+
| `demand-admission` | What happens to an arrival that asks something of the person (§8). |
|
|
201
|
+
|
|
202
|
+
An implementation **MUST** provide `ui-visibility`, `notifications`, and
|
|
203
|
+
`interaction-forgiveness` to claim conformance; the rest are **SHOULD**, since
|
|
204
|
+
not every host has deferral or automation. Whatever it provides **MUST** match
|
|
205
|
+
the vectors exactly.
|
|
206
|
+
|
|
207
|
+
Implementations **MAY** ship additional strategies and **SHOULD** allow
|
|
208
|
+
consumers to supply their own — the type is a contract, not a closed set.
|
|
209
|
+
|
|
210
|
+
### 5.1 Human-readable descriptions
|
|
211
|
+
|
|
212
|
+
The reference implementation pairs each strategy with a `describe(level)`
|
|
213
|
+
returning English prose. This is **NOT** normative and conformance does not
|
|
214
|
+
check it. Wording is a product and localisation decision.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## 6. Direction
|
|
219
|
+
|
|
220
|
+
Two rules constrain every table, and an implementation adding a strategy
|
|
221
|
+
**SHOULD** obey them:
|
|
222
|
+
|
|
223
|
+
1. **Lower energy means less demanded of the person, not less capability.**
|
|
224
|
+
Chrome recedes, notifications batch, defaults lengthen. Features are not
|
|
225
|
+
removed as punishment. The one exception is destructive capability, which
|
|
226
|
+
§5's forgiveness table deliberately makes _harder_ to reach.
|
|
227
|
+
2. **Protection scales inversely with capacity.** Undo windows widen,
|
|
228
|
+
confirmations appear, autosave quickens as energy falls. Slower error
|
|
229
|
+
detection is met with more room to catch errors.
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## 7. Autonomy
|
|
234
|
+
|
|
235
|
+
`autonomy` governs what automated systems may do on the person's behalf without
|
|
236
|
+
being asked. It is the mirror of interaction forgiveness: forgiveness protects
|
|
237
|
+
against the _person's_ mistakes at low energy, autonomy against the _agent's_.
|
|
238
|
+
|
|
239
|
+
Three fields: `confidenceThreshold` (0–1, the minimum confidence to act
|
|
240
|
+
unattended), `allowGeneratedContent` (whether wording may be composed or must
|
|
241
|
+
come from fixed templates), and `maxUnattendedSteps` (how many automated steps
|
|
242
|
+
may chain before control returns).
|
|
243
|
+
|
|
244
|
+
The rule the numbers encode: **what narrows as energy falls is discretion, not
|
|
245
|
+
action.** At Rest the threshold is `1`, admitting only certainty — rule-based
|
|
246
|
+
decisions, never judgement calls — with one step and no composition. Automation
|
|
247
|
+
**MAY** still take a single certain templated action there; an out-of-office
|
|
248
|
+
reply is exactly that shape, and it is _safest_ at Rest precisely because it has
|
|
249
|
+
stopped improvising.
|
|
250
|
+
|
|
251
|
+
A comparison against the threshold **MUST** admit equality: confidence `0.8` at
|
|
252
|
+
a threshold of `0.8` acts. Vectors sample every threshold boundary for this
|
|
253
|
+
reason.
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## 8. Inbound demand
|
|
258
|
+
|
|
259
|
+
**Inbound demand** is anything arriving from outside that asks for the person's
|
|
260
|
+
attention or action: an email, a comment, a review request, an assignment, an
|
|
261
|
+
invitation.
|
|
262
|
+
|
|
263
|
+
This is where the model earns its keep. Every triage system in general use is
|
|
264
|
+
organised around properties of the _message_ — who sent it, what it claims about
|
|
265
|
+
its own urgency, what category it fits. None is organised around the state of
|
|
266
|
+
the _recipient_, which is what actually decides whether an arrival is a small
|
|
267
|
+
task or a crushing weight.
|
|
268
|
+
|
|
269
|
+
### 8.1 The decision
|
|
270
|
+
|
|
271
|
+
Given the level's `demand-admission` config, its `autonomy` config, and an
|
|
272
|
+
arrival described by `originatorTier` (`exempt` / `known` / `unknown`),
|
|
273
|
+
`bearsObligation`, and `confidence` (default `1`), the outcome **MUST** be
|
|
274
|
+
computed in this order:
|
|
275
|
+
|
|
276
|
+
1. `originatorTier` is `exempt` → **live**, no acknowledgment. Unconditional, at
|
|
277
|
+
every level.
|
|
278
|
+
2. The tier passes the level's `originatorThreshold` → **live**.
|
|
279
|
+
3. `bearsObligation` is false → **live**. Informational arrivals ask nothing;
|
|
280
|
+
whether they should _interrupt_ is the notification question, not this one.
|
|
281
|
+
4. The level does not acknowledge → **silent** (captured, no acknowledgment).
|
|
282
|
+
5. `confidence` is below the autonomy threshold → **silent**.
|
|
283
|
+
6. Otherwise → **acknowledge**, at the level's detail, composed only if autonomy
|
|
284
|
+
permits generated content.
|
|
285
|
+
|
|
286
|
+
Reference: `resolveDemandOutcome`; 180 vectors under `decisions.demand`.
|
|
287
|
+
|
|
288
|
+
### 8.2 Invariants for anything acting on the decision
|
|
289
|
+
|
|
290
|
+
The decision is pure. Acting on it is not, and four rules bound what acting may
|
|
291
|
+
look like. An implementation performing these effects **MUST** observe them.
|
|
292
|
+
|
|
293
|
+
1. **Acknowledgment and capture are one act.** An acknowledgment without a
|
|
294
|
+
captured obligation is a promise nobody kept — strictly worse than silence,
|
|
295
|
+
because it converts ambient guilt into explicit written debt. A capture
|
|
296
|
+
without an acknowledgment leaves the originator in silence, which is the
|
|
297
|
+
problem being solved. Where the two cannot be made atomic — and across a
|
|
298
|
+
network they cannot — the capture **MUST** be performed first, because it is
|
|
299
|
+
the reversible half, and **MUST** be rolled back if the acknowledgment fails.
|
|
300
|
+
2. **Acknowledgments state, never promise.** "Received and queued, current
|
|
301
|
+
response horizon Thursday" is a fact. "I'll get back to you soon" is a
|
|
302
|
+
commitment the person's Tuesday self has to keep. Implementations **MUST
|
|
303
|
+
NOT** emit commitments. The horizon **SHOULD** come from the deferral
|
|
304
|
+
strategy, so the queue and the acknowledgment cannot disagree.
|
|
305
|
+
3. **Automated action toward a third party MUST be disclosed as automated.** The
|
|
306
|
+
medium decides the mechanism — `Auto-Submitted: auto-replied` on email
|
|
307
|
+
(RFC 3834, which also prevents responder loops), a system-attributed badge in
|
|
308
|
+
an app. Undisclosed automation speaking in a person's name is the failure
|
|
309
|
+
this design exists to avoid.
|
|
310
|
+
4. **At most once per originator, per window.** Five arrivals from one sender
|
|
311
|
+
while someone is depleted are one social debt, not five. Answering each is
|
|
312
|
+
the volume asymmetry the model is trying to correct.
|
|
313
|
+
|
|
314
|
+
### 8.3 Tiers
|
|
315
|
+
|
|
316
|
+
Tier assignment is the host's: an approved-senders list, a contacts database, an
|
|
317
|
+
org chart. The model consumes the tier and does not compute it.
|
|
318
|
+
|
|
319
|
+
The exempt tier is also what defuses the obvious gaming risk. An originator who
|
|
320
|
+
learns that an acknowledgment means "deprioritised" and escalates through
|
|
321
|
+
another channel only succeeds if their escalation is one the person cannot
|
|
322
|
+
ignore — which is what would have made them exempt in the first place.
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
## 9. Runtime invariants
|
|
327
|
+
|
|
328
|
+
Some requirements cannot be expressed as a vector, because they are about
|
|
329
|
+
sequences rather than functions. They are normative regardless, and they are the
|
|
330
|
+
requirements most often got wrong — each is here because it was observed failing
|
|
331
|
+
in a shipped product.
|
|
332
|
+
|
|
333
|
+
### 9.1 Notification gating
|
|
334
|
+
|
|
335
|
+
An implementation that gates notifications by level **MUST NOT** silently drop
|
|
336
|
+
one. Anything not deliverable now is **deferred** and released when the level
|
|
337
|
+
rises, suppression lifts, or the gate is torn down. A gate being disposed
|
|
338
|
+
**MUST** surface what it still holds.
|
|
339
|
+
|
|
340
|
+
_Why:_ a field client's scheduler destroyed reminders that came due while
|
|
341
|
+
suppressed. From the user's side that is indistinguishable from the app losing
|
|
342
|
+
their data, and it is the fastest way to lose trust in adaptive behavior
|
|
343
|
+
entirely.
|
|
344
|
+
|
|
345
|
+
### 9.2 Time-boxed suppression
|
|
346
|
+
|
|
347
|
+
Any suppression window **MUST** expire on its own. Expiry **MUST** be an emitted
|
|
348
|
+
event, not a condition the host is expected to poll, and suppression **MUST** be
|
|
349
|
+
lifted _before_ the end-of-window event is emitted — otherwise the window
|
|
350
|
+
swallows its own completion notice.
|
|
351
|
+
|
|
352
|
+
_Why:_ focus modes that suppress until manually cleared strand the person on
|
|
353
|
+
exactly the day they forget, and the cost lands on someone who already had none.
|
|
354
|
+
|
|
355
|
+
### 9.3 Deferral
|
|
356
|
+
|
|
357
|
+
Deferral presets **MUST** compute in the person's local time — "tomorrow
|
|
358
|
+
morning" means their morning. The ordering **SHOULD** follow the level: at low
|
|
359
|
+
capacity the one-tap default resurfaces work _later_, not in an hour, because
|
|
360
|
+
resurfacing into the same depletion helps nobody.
|
|
361
|
+
|
|
362
|
+
Because presets are local-time, conformance vectors for them are generated under
|
|
363
|
+
UTC and an implementation replaying them **MUST** do the same.
|
|
364
|
+
|
|
365
|
+
### 9.4 Persistence
|
|
366
|
+
|
|
367
|
+
Persisted state **MUST** round-trip verbatim — every field, not just the level.
|
|
368
|
+
An implementation that stores only the level and rebuilds the rest on read
|
|
369
|
+
produces a new `timestamp` and `origin` on every load, which reads as a fresh
|
|
370
|
+
write to §4 and causes contexts to fight.
|
|
371
|
+
|
|
372
|
+
---
|
|
373
|
+
|
|
374
|
+
## 10. Accessibility requirements
|
|
375
|
+
|
|
376
|
+
Adaptive interfaces can fail people in ways static ones cannot. These are
|
|
377
|
+
requirements, not suggestions.
|
|
378
|
+
|
|
379
|
+
1. **Hiding MUST remove from the accessibility tree.** A level-hidden element
|
|
380
|
+
**MUST NOT** remain focusable or reachable by assistive technology. Visual
|
|
381
|
+
hiding alone leaves a keyboard trap into content that isn't there.
|
|
382
|
+
2. **Focus MUST survive a level change.** If the focused element is hidden by a
|
|
383
|
+
transition, focus **MUST** be moved somewhere sensible and **MUST NOT** be
|
|
384
|
+
left on a removed node.
|
|
385
|
+
3. **Faded chrome MUST reveal on focus, not only on hover.** A control at 10%
|
|
386
|
+
opacity that a keyboard user can tab into but cannot see fails WCAG 2.4.7.
|
|
387
|
+
Every hover-reveal rule **MUST** have a `:focus-within` twin.
|
|
388
|
+
4. **Level transitions MUST be announceable.** A person using a screen reader
|
|
389
|
+
**MUST** have some way to know the interface changed. The host chooses the
|
|
390
|
+
mechanism; silence is not an option.
|
|
391
|
+
5. **Reduced motion MUST be honored.** Transitions between levels **MUST** be
|
|
392
|
+
suppressed under `prefers-reduced-motion: reduce`.
|
|
393
|
+
6. **Contrast obligations are the host's and MUST be reachable.** The reference
|
|
394
|
+
opacity values are a design default, not a conformance claim: at Low and Rest
|
|
395
|
+
the resting chrome opacity does not meet WCAG 1.4.11 for non-text contrast.
|
|
396
|
+
An implementation **MUST** make these values overridable and **SHOULD**
|
|
397
|
+
raise them under `prefers-contrast: more`.
|
|
398
|
+
|
|
399
|
+
---
|
|
400
|
+
|
|
401
|
+
## 11. Conformance
|
|
402
|
+
|
|
403
|
+
An implementation conforms if:
|
|
404
|
+
|
|
405
|
+
1. It represents state per §3 and serializes per the schema.
|
|
406
|
+
2. It reconciles per §4, including antisymmetry.
|
|
407
|
+
3. It provides at least the required strategies of §5, matching the vectors exactly.
|
|
408
|
+
4. It observes the runtime invariants of §9 for whichever runtimes it provides.
|
|
409
|
+
5. It meets §10 for whichever surfaces it renders.
|
|
410
|
+
|
|
411
|
+
The vectors are the mechanical part. Load `conformance.json`, replay each
|
|
412
|
+
section against your implementation, and compare. The reference implementation
|
|
413
|
+
does exactly this in `test/conformance.test.ts`, which is a reasonable model for
|
|
414
|
+
a port's own suite.
|
|
415
|
+
|
|
416
|
+
Vector sections: `levels`, `cycle`, `strategies`, `presence`,
|
|
417
|
+
`decisions.notification`, `decisions.demand`, `deferral`, `reconciliation`,
|
|
418
|
+
`metrics`, `externalLevelMapping`.
|
|
419
|
+
|
|
420
|
+
### 11.1 Versioning
|
|
421
|
+
|
|
422
|
+
The vectors carry the reference implementation's version. Within a major
|
|
423
|
+
version, existing vectors **MUST NOT** change meaning; sections and vectors
|
|
424
|
+
**MAY** be added. A change to a shipped table's values is a breaking change to
|
|
425
|
+
this specification, not just to the library.
|
|
426
|
+
|
|
427
|
+
---
|
|
428
|
+
|
|
429
|
+
## 12. What is deliberately not specified
|
|
430
|
+
|
|
431
|
+
- **Wording.** Every user-facing string is a product decision.
|
|
432
|
+
- **Visual design.** The reference stylesheet is one interpretation.
|
|
433
|
+
- **How a level is chosen.** A dial, a keystroke, a menu — the model requires
|
|
434
|
+
only that the person can set it directly.
|
|
435
|
+
- **Classification.** How a host decides that an arrival bears an obligation, or
|
|
436
|
+
what tier an originator is in, is the host's problem entirely. The model
|
|
437
|
+
consumes the answer and the confidence attached to it.
|
|
438
|
+
- **Transport.** How states reach each other — shared storage, IPC, a sync
|
|
439
|
+
server — is out of scope. The schema and §4 are what make any transport work.
|
package/api-surface.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
2
|
+
"version": "1.0.0",
|
|
3
3
|
"entryPoints": [
|
|
4
4
|
{
|
|
5
5
|
"specifier": "@kumbatio/energy-system",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"ENERGY_SOURCE_VALUES",
|
|
11
11
|
"UNPRODUCED_ORIGIN",
|
|
12
12
|
"UNPRODUCED_TIMESTAMP",
|
|
13
|
+
"autonomyStrategy",
|
|
13
14
|
"createDeferralPresets",
|
|
14
15
|
"createEnergyEngine",
|
|
15
16
|
"createEnergyOrigin",
|
|
@@ -22,6 +23,7 @@
|
|
|
22
23
|
"cycleEnergyLevel",
|
|
23
24
|
"deferralStrategy",
|
|
24
25
|
"defineEnergyPresence",
|
|
26
|
+
"demandAdmissionStrategy",
|
|
25
27
|
"getEnergyLevel",
|
|
26
28
|
"getEnergyLevels",
|
|
27
29
|
"getEnergyMetrics",
|
|
@@ -31,6 +33,8 @@
|
|
|
31
33
|
"isEnergySource",
|
|
32
34
|
"isHigherEnergy",
|
|
33
35
|
"isNotificationPriority",
|
|
36
|
+
"isOriginatorTier",
|
|
37
|
+
"isPreferredEnergyState",
|
|
34
38
|
"isPresenceVisible",
|
|
35
39
|
"isSessionExpired",
|
|
36
40
|
"isUnproducedState",
|
|
@@ -40,6 +44,7 @@
|
|
|
40
44
|
"presenceAtOrAbove",
|
|
41
45
|
"presenceAtOrBelow",
|
|
42
46
|
"resolveDeferral",
|
|
47
|
+
"resolveDemandOutcome",
|
|
43
48
|
"resolveEnergyPresence",
|
|
44
49
|
"resolveNotificationOutcome",
|
|
45
50
|
"sessionRemainingMs",
|
|
@@ -47,12 +52,20 @@
|
|
|
47
52
|
"uiVisibilityStrategy"
|
|
48
53
|
],
|
|
49
54
|
"types": [
|
|
55
|
+
"AcknowledgmentDetail",
|
|
50
56
|
"AdaptationStrategy",
|
|
57
|
+
"AutonomyConfig",
|
|
51
58
|
"CognitiveProfile",
|
|
52
59
|
"DecisionCapacity",
|
|
53
60
|
"DeferralConfig",
|
|
54
61
|
"DeferralPreset",
|
|
55
62
|
"DeferralPresetOptions",
|
|
63
|
+
"DemandAcknowledgment",
|
|
64
|
+
"DemandAdmission",
|
|
65
|
+
"DemandAdmissionConfig",
|
|
66
|
+
"DemandInput",
|
|
67
|
+
"DemandOutcome",
|
|
68
|
+
"DemandOutcomeReason",
|
|
56
69
|
"EnergyChangeListener",
|
|
57
70
|
"EnergyClock",
|
|
58
71
|
"EnergyEngine",
|
|
@@ -86,6 +99,7 @@
|
|
|
86
99
|
"NotificationGate",
|
|
87
100
|
"NotificationGateOptions",
|
|
88
101
|
"NotificationPriority",
|
|
102
|
+
"OriginatorTier",
|
|
89
103
|
"PublishOutcome",
|
|
90
104
|
"StartFocusSessionOptions",
|
|
91
105
|
"TaskComplexity",
|
|
@@ -161,6 +175,25 @@
|
|
|
161
175
|
"defaultPresetId",
|
|
162
176
|
"orderedPresetIds"
|
|
163
177
|
],
|
|
178
|
+
"DemandAcknowledgment": [
|
|
179
|
+
"allowGeneratedContent",
|
|
180
|
+
"detail"
|
|
181
|
+
],
|
|
182
|
+
"DemandOutcome": [
|
|
183
|
+
"acknowledgment",
|
|
184
|
+
"admission",
|
|
185
|
+
"reason"
|
|
186
|
+
],
|
|
187
|
+
"DemandInput": [
|
|
188
|
+
"bearsObligation",
|
|
189
|
+
"confidence",
|
|
190
|
+
"originatorTier"
|
|
191
|
+
],
|
|
192
|
+
"DemandAdmissionConfig": [
|
|
193
|
+
"acknowledge",
|
|
194
|
+
"acknowledgmentDetail",
|
|
195
|
+
"originatorThreshold"
|
|
196
|
+
],
|
|
164
197
|
"EnergyEngineOptions": [
|
|
165
198
|
"autoStart",
|
|
166
199
|
"clock",
|
|
@@ -292,6 +325,11 @@
|
|
|
292
325
|
"confirmDestructive",
|
|
293
326
|
"undoWindowMs"
|
|
294
327
|
],
|
|
328
|
+
"AutonomyConfig": [
|
|
329
|
+
"allowGeneratedContent",
|
|
330
|
+
"confidenceThreshold",
|
|
331
|
+
"maxUnattendedSteps"
|
|
332
|
+
],
|
|
295
333
|
"EnergyState": [
|
|
296
334
|
"level",
|
|
297
335
|
"origin",
|