@bilig/workbook 0.96.0 → 0.103.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/README.md +155 -449
- package/dist/features-public.d.ts +2 -0
- package/dist/features-public.js +3 -0
- package/dist/features-public.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/model-plan-result.d.ts +1 -0
- package/dist/model-plan-result.js +17 -0
- package/dist/model-plan-result.js.map +1 -1
- package/dist/model.d.ts +1 -0
- package/dist/model.js +21 -14
- package/dist/model.js.map +1 -1
- package/dist/prepare.d.ts +22 -0
- package/dist/prepare.js +41 -0
- package/dist/prepare.js.map +1 -0
- package/dist/requirements.d.ts +4 -3
- package/dist/requirements.js +50 -7
- package/dist/requirements.js.map +1 -1
- package/dist/result.d.ts +2 -2
- package/dist/result.js +1 -0
- package/dist/result.js.map +1 -1
- package/dist/run-apply.d.ts +17 -0
- package/dist/run-apply.js +274 -0
- package/dist/run-apply.js.map +1 -0
- package/dist/run-check-verification.d.ts +8 -0
- package/dist/run-check-verification.js +174 -0
- package/dist/run-check-verification.js.map +1 -0
- package/dist/run-data.d.ts +6 -0
- package/dist/run-data.js +120 -0
- package/dist/run-data.js.map +1 -0
- package/dist/run-description.js +12 -9
- package/dist/run-description.js.map +1 -1
- package/dist/run.d.ts +2 -2
- package/dist/run.js +4 -560
- package/dist/run.js.map +1 -1
- package/dist/schema.d.ts +3 -2
- package/dist/schema.js +120 -7
- package/dist/schema.js.map +1 -1
- package/dist/testing.d.ts +34 -0
- package/dist/testing.js +85 -0
- package/dist/testing.js.map +1 -0
- package/fixtures/runtime-requirements.json +72 -0
- package/package.json +19 -4
package/README.md
CHANGED
|
@@ -7,30 +7,34 @@ predictable, inspectable, verifiable, and never dependent on hardcoded business
|
|
|
7
7
|
models or human spreadsheet UI assumptions.
|
|
8
8
|
|
|
9
9
|
Use this package when a consumer wants to define their own workbook model and
|
|
10
|
-
hand a runtime a portable plan.
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
hand a runtime a portable plan. Bilig supplies the generic model API, selectors,
|
|
11
|
+
formula helpers, checks, JSON-safe transport data, validators, and run-result
|
|
12
|
+
proof shapes. It does not import an engine, start a server, calculate formulas,
|
|
13
|
+
ship business templates, or depend on `@bilig/core`, `@bilig/headless`,
|
|
14
|
+
`@bilig/agent-api`, `zod`, or `effect`.
|
|
13
15
|
|
|
14
16
|
```sh
|
|
15
17
|
pnpm add @bilig/workbook
|
|
16
18
|
```
|
|
17
19
|
|
|
20
|
+
## Use These First
|
|
21
|
+
|
|
22
|
+
Most consumers should start with only these names:
|
|
23
|
+
|
|
24
|
+
- `defineModel`
|
|
25
|
+
- `formula`
|
|
26
|
+
- `prepareWorkbookAction`
|
|
27
|
+
- `runWorkbookPlan`
|
|
28
|
+
- `describeModel`, `describePlan`, `describeRunResult`
|
|
29
|
+
|
|
30
|
+
That path lets an agent define intent, inspect it before execution, transport it
|
|
31
|
+
as plain data, run it through a runtime-owned adapter, and verify the returned
|
|
32
|
+
proof without knowing anything about a rendered spreadsheet UI.
|
|
33
|
+
|
|
18
34
|
## The Shape
|
|
19
35
|
|
|
20
36
|
```ts
|
|
21
|
-
import {
|
|
22
|
-
defineModel,
|
|
23
|
-
describePlan,
|
|
24
|
-
describeRunResult,
|
|
25
|
-
describeRuntimeRequirements,
|
|
26
|
-
formula,
|
|
27
|
-
planWorkbookAction,
|
|
28
|
-
runWorkbookPlan,
|
|
29
|
-
toPlanData,
|
|
30
|
-
verifyPlan,
|
|
31
|
-
verifyPlanData,
|
|
32
|
-
workbookPlanId,
|
|
33
|
-
} from '@bilig/workbook'
|
|
37
|
+
import { defineModel, describeRunResult, formula, prepareWorkbookAction, runWorkbookPlan } from '@bilig/workbook'
|
|
34
38
|
|
|
35
39
|
export const model = defineModel({
|
|
36
40
|
name: 'named-range-formula',
|
|
@@ -56,253 +60,82 @@ export const model = defineModel({
|
|
|
56
60
|
},
|
|
57
61
|
})
|
|
58
62
|
|
|
59
|
-
const
|
|
60
|
-
if (
|
|
63
|
+
const prepared = prepareWorkbookAction(model, 'calculate')
|
|
64
|
+
if (prepared.status === 'failed') throw new Error(prepared.errors[0]?.message)
|
|
61
65
|
|
|
62
|
-
const
|
|
63
|
-
const requirements = describeRuntimeRequirements(planned.plan)
|
|
64
|
-
const planForLogs = describePlan(planned.plan)
|
|
65
|
-
const planIdForLogs = workbookPlanId(planned.plan)
|
|
66
|
-
const transportedPlan = JSON.parse(JSON.stringify(toPlanData(planned.plan)))
|
|
67
|
-
const transportProof = verifyPlanData(transportedPlan)
|
|
68
|
-
|
|
69
|
-
const result = await runWorkbookPlan(transportedPlan, adapter, { strict: true })
|
|
66
|
+
const result = await runWorkbookPlan(prepared.planData, adapter, { strict: true })
|
|
70
67
|
const resultForLogs = describeRunResult(result)
|
|
71
68
|
```
|
|
72
69
|
|
|
73
|
-
|
|
70
|
+
The core flow is deliberately boring:
|
|
74
71
|
|
|
75
72
|
1. `defineModel` freezes a consumer-defined model.
|
|
76
73
|
2. `find` returns generic refs.
|
|
77
74
|
3. `checks` declares facts the runtime must prove.
|
|
78
75
|
4. An action builds workbook intent.
|
|
79
|
-
5. `
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
76
|
+
5. `prepareWorkbookAction` verifies the plan, computes requirements, emits
|
|
77
|
+
JSON-safe `planData`, and gives the exact plan a stable id.
|
|
78
|
+
6. `runWorkbookPlan(..., { strict: true })` fails closed unless the adapter
|
|
79
|
+
returns plan-bound apply proof, revision proof, resolved refs, command
|
|
80
|
+
receipts, check proof, and no unverified apply facts.
|
|
84
81
|
|
|
85
82
|
## Which Package
|
|
86
83
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
`@bilig/
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
`@bilig/workbook/
|
|
99
|
-
`@bilig/workbook/
|
|
100
|
-
`@bilig/workbook/
|
|
101
|
-
|
|
102
|
-
##
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
-
|
|
110
|
-
-
|
|
111
|
-
-
|
|
112
|
-
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
-
|
|
117
|
-
-
|
|
118
|
-
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
- `
|
|
125
|
-
- `
|
|
126
|
-
- `
|
|
127
|
-
- `
|
|
128
|
-
- `
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
- `
|
|
133
|
-
- `
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
mutates workbook
|
|
141
|
-
|
|
142
|
-
Model action manifests are frozen null-prototype maps. Consumers can use normal
|
|
143
|
-
business-agnostic action names, including names such as `toString` or
|
|
144
|
-
`constructor`, and `planWorkbookAction` only runs own actions from the manifest.
|
|
145
|
-
Prototype-inherited actions are ignored, so an agent can treat the action list as
|
|
146
|
-
the full executable surface.
|
|
147
|
-
Public helper namespaces are frozen as well: `find`, `check`, and `formula`
|
|
148
|
-
cannot be patched after import, and factory-created check/find helpers return
|
|
149
|
-
frozen API objects too.
|
|
150
|
-
Model config and action objects are read as data too: `defineModel` requires
|
|
151
|
-
object-record model roots plus own data properties for `actions` entries and
|
|
152
|
-
for action-object `run`, `description`, and `input`. Accessor-backed model
|
|
153
|
-
metadata is rejected before any getter can run.
|
|
154
|
-
`inspectModel` and `describeModel` use the same manifest boundary, so model
|
|
155
|
-
names, descriptions, action maps, and action metadata can be inspected without
|
|
156
|
-
triggering hidden getters. Class/custom-prototype model roots are rejected, while
|
|
157
|
-
action maps and action objects keep their existing own-field-only prototype
|
|
158
|
-
behavior. `inspectModel` returns a frozen manifest snapshot.
|
|
159
|
-
The description layer is frozen too: `describeRef`, `describePlan`,
|
|
160
|
-
`describePlanResult`, and `describeRunResult` return JSON-safe objects whose
|
|
161
|
-
nested refs, commands, checks, apply proof, undo ops, and errors cannot be
|
|
162
|
-
mutated after an agent has inspected them.
|
|
163
|
-
Validation and proof results follow the same rule: `checkInput`,
|
|
164
|
-
`checkPlanData`, `verifyPlan`, `verifyModel`, and `verifyWorkbookReadbacks`
|
|
165
|
-
return frozen verdict containers, arrays, generated issues, and readback-derived
|
|
166
|
-
checks.
|
|
167
|
-
`checkWorkbookReadbackProof(data)` validates a transported `{ checks,
|
|
168
|
-
readbacks }` proof object in one call, returning either frozen verified proof or
|
|
169
|
-
stable readback issues. `isWorkbookReadbackProof(data)` is the boolean guard over
|
|
170
|
-
that same proof boundary.
|
|
171
|
-
Ref, ref-data, feature, command, receipt, result, run-result-description, and
|
|
172
|
-
runtime-adapter validators return frozen verdicts too, so every public
|
|
173
|
-
`{ status, issues }` handoff has the same inspect-once behavior.
|
|
174
|
-
Feature plugin manifests, nested command descriptors, projection interceptors,
|
|
175
|
-
and UI contributions must be object-record data. Class/custom-prototype feature
|
|
176
|
-
metadata is rejected before registration, and exported command descriptor
|
|
177
|
-
normalization reads own data properties without invoking accessors.
|
|
178
|
-
`runWorkbookPlan` and `runWorkbookAction` return frozen run results too,
|
|
179
|
-
including changed summaries, checks, errors, apply proof, undo refs, and
|
|
180
|
-
unverified proof notes.
|
|
181
|
-
`planWorkbookAction` also validates that boundary before reading action metadata
|
|
182
|
-
or running model code. Invalid manifests return a structured `invalid_model`
|
|
183
|
-
failure instead of making the agent catch an accessor side effect. Planned and
|
|
184
|
-
failed action-plan result wrappers are frozen before they are returned.
|
|
185
|
-
Action helper calls fail closed during planning too: write, clear, format, and
|
|
186
|
-
low-level-op helpers reject malformed targets, non-literal values, invalid
|
|
187
|
-
format options, invalid add-op options, class/custom-prototype option roots, and
|
|
188
|
-
accessor-backed op payloads before a plan is returned.
|
|
189
|
-
Check helper calls use the same boundary: malformed targets, readback options,
|
|
190
|
-
custom check options, class/custom-prototype option roots, sparse ref arrays, and
|
|
191
|
-
accessor-backed check payloads are rejected before a check is recorded.
|
|
192
|
-
Formula helpers also normalize as plain data: raw formula options, explicit
|
|
193
|
-
inputs, labels, and function argument arrays reject sparse, accessor-backed, or
|
|
194
|
-
class/custom-prototype payloads before formula intent is returned.
|
|
195
|
-
Ref transport helpers return frozen plain data and frozen arrays, so a ref that
|
|
196
|
-
an agent inspected cannot be mutated behind the same handoff object. Transported
|
|
197
|
-
ref nodes and nested selector records must be object-record data; class/custom-
|
|
198
|
-
prototype ref records are rejected before hydration or persisted proof use.
|
|
199
|
-
`verifyPlan` also treats plans as data: malformed, sparse, or accessor-backed
|
|
200
|
-
handoff objects return an `invalid_plan` issue instead of executing hidden
|
|
201
|
-
properties or throwing at the caller.
|
|
202
|
-
`verifyModel` keeps the same behavior at whole-model scope: invalid,
|
|
203
|
-
array-backed, or accessor-backed manifests return an invalid verdict with an
|
|
204
|
-
`invalid_model` error and no actions.
|
|
205
|
-
Its `{ inputs }` option is data-only too: accessor-backed or
|
|
206
|
-
class/custom-prototype option payloads and per-action inputs produce structured
|
|
207
|
-
`invalid_action_input` results without running hidden consumer code.
|
|
208
|
-
|
|
209
|
-
## Selectors
|
|
210
|
-
|
|
211
|
-
Selectors are not a human spreadsheet UI. They are stable intent for runtimes and
|
|
212
|
-
agents.
|
|
213
|
-
|
|
214
|
-
- `findTable({ headers })` means "find a table with all these headers." Header
|
|
215
|
-
order is normalized, duplicate headers are rejected, and matching is
|
|
216
|
-
case-sensitive after trimming.
|
|
217
|
-
- `findRows({ table, where })` means "find rows in this table matching this
|
|
218
|
-
predicate." `eq` and `neq` accept any JSON literal; `contains` and
|
|
219
|
-
`startsWith` accept strings; ordered comparisons accept numbers or strings.
|
|
220
|
-
- `findRange` is the escape hatch for an explicit range when the consumer really
|
|
221
|
-
has one. It validates and canonicalizes addresses before runtime handoff.
|
|
222
|
-
|
|
223
|
-
Refs are frozen data. Helpers such as `table.column("result")` and
|
|
224
|
-
`rows.column("result")` are non-enumerable, so JSON descriptions stay data-first.
|
|
225
|
-
Use `toWorkbookRefData` or `describeRef` when a ref must cross a JSON boundary.
|
|
226
|
-
Use `hydrateWorkbookRef` or `hydrateWorkbookRefs` after transport to regain the
|
|
227
|
-
local helpers. `verifyPlanData(describePlan(plan))` checks transported plan data
|
|
228
|
-
without requiring the consumer's private `refs` object shape.
|
|
229
|
-
Ref collection and ref hydration only inspect enumerable own data properties.
|
|
230
|
-
Accessors are ignored instead of invoked, so hidden consumer getters cannot run
|
|
231
|
-
while an agent is planning, verifying, logging, or hydrating workbook intent.
|
|
232
|
-
Array entries follow the same rule, and ref cloning copies only known ref fields
|
|
233
|
-
instead of spreading extra enumerable properties.
|
|
234
|
-
Selector creation follows the same data boundary. `findTable`, `findColumn`,
|
|
235
|
-
`findRange`, and `findRows` read option objects, row predicates, and header
|
|
236
|
-
arrays through own data properties, rejecting accessor-backed fields before any
|
|
237
|
-
getter can run.
|
|
238
|
-
Transported row refs use that same selector contract too: ref-data guards,
|
|
239
|
-
collection, cloning, and hydration reject operator/value pairs that `findRows`
|
|
240
|
-
would reject. Transported ref data is an object-record boundary at every node:
|
|
241
|
-
range payloads, row predicates, and nested table/rows refs cannot be class
|
|
242
|
-
instances with hidden behavior.
|
|
243
|
-
|
|
244
|
-
For full action handoff, use `toPlanData(plan)` before JSON transport. A runtime
|
|
245
|
-
can call `checkPlanData(data)` to get structured path-based issues before
|
|
246
|
-
hydration, call `hydratePlanData(data)` to regain frozen refs and helper
|
|
247
|
-
methods, or pass the data directly to `describeRuntimeRequirements(data)` and
|
|
248
|
-
`runWorkbookPlan(data, adapter)`. `runWorkbookPlan` returns a failed result with
|
|
249
|
-
`invalid_plan_data` errors instead of throwing or calling `apply` when
|
|
250
|
-
transported plan data is malformed. Invalid transported action input and check
|
|
251
|
-
proof keep nested JSON paths such as `input.rows[1]` and
|
|
252
|
-
`checks[0].proof.when`, so an agent can repair the exact payload field before
|
|
253
|
-
hydration. Plan-data guards only trust own payload fields; inherited
|
|
254
|
-
prototype fields never satisfy the transport contract. Transported plan arrays
|
|
255
|
-
must contain own enumerable data entries too; holes, non-enumerable entries, or
|
|
256
|
-
accessor-backed entries are rejected without running getters. The plan root and
|
|
257
|
-
nested plan entries such as commands, changes, checks, formula labels, and
|
|
258
|
-
expectations must be record-shaped payloads, not arrays with attached fields.
|
|
259
|
-
The hydrated plan
|
|
260
|
-
exposes `refs: { refsUsed }` instead of the consumer's private model-shaped
|
|
261
|
-
`refs` object, so transported execution stays generic. A valid
|
|
262
|
-
`checkPlanData(data)` result returns canonical plan data, stripping caller-owned
|
|
263
|
-
scratch fields before ids, hydration, requirements, or execution inspect it.
|
|
264
|
-
|
|
265
|
-
## Action Input
|
|
266
|
-
|
|
267
|
-
Action input is JSON-safe data, not a schema-framework object. Action metadata
|
|
268
|
-
can describe generic input with `json`, `object`, `array`, `string`, `number`,
|
|
269
|
-
`boolean`, and `null` kinds. `checkInput(description, value)` returns a frozen
|
|
270
|
-
`{ status, input, issues }` result so an agent can reject malformed tool payloads
|
|
271
|
-
before running workbook model code. Omitted input is valid unless the top-level
|
|
272
|
-
description sets `required: true`, so agents can distinguish an optional payload
|
|
273
|
-
from a malformed payload. `planWorkbookAction` uses the same check when an action
|
|
274
|
-
declares input metadata and preserves each failed input issue as a run error
|
|
275
|
-
with `path` and `issueCode`, so agents can branch without parsing messages.
|
|
276
|
-
JSON-safety failures keep the nested offending path too, such as
|
|
277
|
-
`input.items[2].amount`. Normalized payloads preserve consumer-owned JSON keys
|
|
278
|
-
as data, including names like `__proto__` and `constructor`, instead of letting
|
|
279
|
-
them affect object prototypes.
|
|
280
|
-
Action input payloads and input-description metadata must be enumerable own data
|
|
281
|
-
properties. Accessors are rejected without invoking them, so tool payload
|
|
282
|
-
validation cannot run hidden consumer code while an agent is planning.
|
|
283
|
-
|
|
284
|
-
## Formulas
|
|
285
|
-
|
|
286
|
-
`@bilig/workbook` creates formula expressions. `@bilig/formula` parses and
|
|
287
|
-
normalizes formula text. `@bilig/core` or an app runtime calculates it.
|
|
288
|
-
|
|
289
|
-
Formula helpers keep formula text, workbook dependencies, and formula labels
|
|
290
|
-
separate. A planned formula write includes the formula string, the refs used to
|
|
291
|
-
build it, and a `labels` array mapping each formula token to the workbook ref it
|
|
292
|
-
represents. Runtime adapters use those labels to materialize table columns,
|
|
293
|
-
filtered rows, names, and ranges without reverse-engineering hidden JS helpers.
|
|
294
|
-
Plan verification parses formula text and checks labels against formula reference
|
|
295
|
-
tokens, so substrings and quoted string literals do not count as dependency
|
|
296
|
-
proof.
|
|
297
|
-
For custom formula text, use `formula.raw(source, { inputs })`; pass
|
|
298
|
-
`labels: [{ name, ref }]` when the raw formula uses custom tokens. For
|
|
299
|
-
spreadsheet string literals, use `formula.text(value)`. Bare strings are not
|
|
300
|
-
formula operands because agents should not guess whether a string is code, a
|
|
301
|
-
label, a named range, or user text.
|
|
302
|
-
|
|
303
|
-
## Runtime Adapter
|
|
304
|
-
|
|
305
|
-
`@bilig/workbook` does not execute plans. A runtime owns that:
|
|
84
|
+
| Package | Choose when | Do not use for |
|
|
85
|
+
| ------------------ | --------------------------------------------------------------------------------------------- | -------------------------------------------------- |
|
|
86
|
+
| `@bilig/workbook` | Defining generic agent intent, refs, formulas, checks, plan data, schemas, and proof handoff. | Calculating formulas or owning workbook state. |
|
|
87
|
+
| `@bilig/workpaper` | Running workbook tools, MCP, or product workflows around persisted WorkPaper state. | Designing a reusable model API for other runtimes. |
|
|
88
|
+
| `@bilig/headless` | Owning workbook state inside Node with formula recalculation and import/export. | Publishing generic agent intent contracts. |
|
|
89
|
+
| `@bilig/core` | Implementing calculation or mutation internals. | Consumer-facing agent model definitions. |
|
|
90
|
+
|
|
91
|
+
The root export keeps the complete contract. Subpath exports are available when
|
|
92
|
+
an agent wants a smaller import map: `@bilig/workbook/model`,
|
|
93
|
+
`@bilig/workbook/prepare`, `@bilig/workbook/find`,
|
|
94
|
+
`@bilig/workbook/check`, `@bilig/workbook/formula`,
|
|
95
|
+
`@bilig/workbook/verify`, `@bilig/workbook/runtime`,
|
|
96
|
+
`@bilig/workbook/command`, `@bilig/workbook/features`,
|
|
97
|
+
`@bilig/workbook/testing`, and `@bilig/workbook/schema`.
|
|
98
|
+
|
|
99
|
+
## Mental Model
|
|
100
|
+
|
|
101
|
+
Consumers define models. Bilig does not ship hardcoded business models in this
|
|
102
|
+
package.
|
|
103
|
+
|
|
104
|
+
Models are plain:
|
|
105
|
+
|
|
106
|
+
- `find(workbook)` binds the workbook parts the model needs.
|
|
107
|
+
- `checks({ refs, workbook })` declares proof the runtime must provide.
|
|
108
|
+
- `actions` write formulas, values, formatting, clears, or guarded low-level ops.
|
|
109
|
+
- `prepareWorkbookAction(model, action)` is the canonical preflight for agents.
|
|
110
|
+
|
|
111
|
+
Refs are generic:
|
|
112
|
+
|
|
113
|
+
- `findName(name)` binds a named workbook ref.
|
|
114
|
+
- `findTable({ name, sheetName, headers })` binds a table by stable traits.
|
|
115
|
+
- `findColumn({ table, name })` and `table.column(name)` bind columns.
|
|
116
|
+
- `findRows({ table, where })` binds filtered rows.
|
|
117
|
+
- `findRange(input)` exists for explicit ranges when a consumer truly has one.
|
|
118
|
+
|
|
119
|
+
Formulas stay symbolic until a runtime materializes them:
|
|
120
|
+
|
|
121
|
+
- `formula.multiply(refs.input, refs.factor)` builds formula intent.
|
|
122
|
+
- `formula.raw(source, { inputs, labels })` accepts custom formula text.
|
|
123
|
+
- `formula.text(value)` creates a spreadsheet string literal.
|
|
124
|
+
- `@bilig/formula` parses and normalizes the formula language.
|
|
125
|
+
- `@bilig/core` or an app runtime calculates formulas.
|
|
126
|
+
|
|
127
|
+
Checks are part of the plan, not comments:
|
|
128
|
+
|
|
129
|
+
- `check.exists(ref)` proves the ref resolved.
|
|
130
|
+
- `check.noFormulaErrors(ref)` proves a formula target is clean.
|
|
131
|
+
- `check.valueEquals(ref, value)` proves a runtime value.
|
|
132
|
+
- `check.formulaEquals(ref, formula)` proves the runtime formula matches intent.
|
|
133
|
+
- `check.custom(options)` carries a runtime-owned proof contract.
|
|
134
|
+
|
|
135
|
+
## Agent-Safe Runtime
|
|
136
|
+
|
|
137
|
+
`@bilig/workbook` never mutates a workbook by itself. A runtime provides an
|
|
138
|
+
adapter:
|
|
306
139
|
|
|
307
140
|
```ts
|
|
308
141
|
const adapter = {
|
|
@@ -310,123 +143,42 @@ const adapter = {
|
|
|
310
143
|
const ops = materializeForThisRuntime(plan)
|
|
311
144
|
return {
|
|
312
145
|
status: 'applied',
|
|
146
|
+
planId: workbookPlanId(plan),
|
|
147
|
+
baseRevision: currentRevision,
|
|
148
|
+
revision: currentRevision + 1,
|
|
313
149
|
previewOps: ops,
|
|
314
150
|
appliedOps: ops,
|
|
315
|
-
|
|
151
|
+
commandReceipts: receiptsFor(plan, ops),
|
|
316
152
|
undo: { id: 'undo-1' },
|
|
317
153
|
}
|
|
318
154
|
},
|
|
319
155
|
read(targets, plan) {
|
|
320
|
-
return targets
|
|
156
|
+
return readTargetsFromRuntime(targets, plan)
|
|
321
157
|
},
|
|
322
158
|
verifyChecks(checks, plan) {
|
|
323
|
-
return checks
|
|
159
|
+
return proveChecksFromRuntime(checks, plan)
|
|
324
160
|
},
|
|
325
161
|
}
|
|
326
162
|
```
|
|
327
163
|
|
|
328
|
-
`runWorkbookPlan
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
verifies the declared checks directly.
|
|
347
|
-
Adapter methods are own data functions, not getters or inherited prototype
|
|
348
|
-
methods. Accessor-backed `apply`, `read`, or `verifyChecks` entries are treated
|
|
349
|
-
as missing capabilities without running hidden consumer code.
|
|
350
|
-
If an adapter returns both `previewOps` and `appliedOps`, the result reports
|
|
351
|
-
whether they matched. If the adapter returns neither, the run records an
|
|
352
|
-
unverified apply fact. Use `runWorkbookPlan(plan, adapter, { requireApplyProof:
|
|
353
|
-
true })` when an agent must fail closed instead of accepting an unproved apply.
|
|
354
|
-
Use `workbookPlanId(plan)` when the runtime needs to bind apply evidence to the
|
|
355
|
-
exact generic plan it received. If an adapter returns `planId`, `@bilig/workbook`
|
|
356
|
-
rejects stale or mismatched ids; `{ requirePlanId: true }` fails closed when the
|
|
357
|
-
adapter omits that binding. Apply summaries may also carry `baseRevision` and
|
|
358
|
-
`revision`, so a later agent can inspect which workbook revision the proof
|
|
359
|
-
claimed to apply against.
|
|
360
|
-
Use `{ strict: true }` as the single agent-safe option when callers want
|
|
361
|
-
agent-grade proof without remembering multiple flags. Strict mode requires
|
|
362
|
-
at least one planned check before mutating plans apply, apply proof, plan-id
|
|
363
|
-
proof, base and applied workbook revisions, no unverified apply facts, concrete
|
|
364
|
-
applied ops for every planned command, resolved-ref proof that matches each
|
|
365
|
-
ref-targeting command's planned target/input refs, and proof on every passed
|
|
366
|
-
check.
|
|
367
|
-
Run options are data-only too: accessor-backed or non-boolean proof options
|
|
368
|
-
return `invalid_run_options` before any adapter method is called. Optional
|
|
369
|
-
`expectedBaseRevision` must be a non-negative safe integer and fails closed when
|
|
370
|
-
the runtime applies against a different base revision.
|
|
371
|
-
Use `workbookActionCommandDigest(command)` when a runtime needs to bind
|
|
372
|
-
materialized ops to a specific planned command. Adapter apply results can return
|
|
373
|
-
`commandReceipts`, one per planned command, with the command index, command kind,
|
|
374
|
-
command digest, preview ops, applied ops, optional `resolvedRefs` proof, and
|
|
375
|
-
optional `formulaLabels` proof for the parsed formula labels used during
|
|
376
|
-
materialization.
|
|
377
|
-
`@bilig/workbook` rejects stale digests, missing commands, duplicate command
|
|
378
|
-
indexes, mismatched receipt ops, receipts whose ops do not match the planned
|
|
379
|
-
command's concrete workbook op, or receipts whose flattened ops disagree with
|
|
380
|
-
the apply-level ops. With `{ requireApplyProof: true }`, a plan with commands
|
|
381
|
-
fails closed unless those command receipts are present. With `{ strict: true }`,
|
|
382
|
-
empty per-command applied ops or stale resolved-ref proof fail closed too.
|
|
383
|
-
The repository-owned `@bilig/core` adapter now supplies that strict proof for
|
|
384
|
-
generic model actions: each command receipt includes materialized applied ops and
|
|
385
|
-
the resolved target/input refs that produced them; single-cell formula receipts
|
|
386
|
-
also include the generic label-to-reference replacements used to materialize the
|
|
387
|
-
formula. Apply summaries include base/applied revisions, and core-owned
|
|
388
|
-
`exists` / `noFormulaErrors` check verification attaches proof to passed checks.
|
|
389
|
-
Formula readback proof uses the same parsed-label materialization, so agents can
|
|
390
|
-
compare symbolic formula intent to runtime formula strings without substring
|
|
391
|
-
replacement or UI-coordinate assumptions. `apps/bilig` can therefore accept
|
|
392
|
-
transported `WorkbookPlanData` directly through its Zero mutation path, run it
|
|
393
|
-
with `strict: true` and the current expected base revision, persist the original
|
|
394
|
-
plan, the concrete applied ops, and the frozen run-result description, and roll
|
|
395
|
-
back engine ops if post-apply readback or check proof fails.
|
|
396
|
-
Runtime apply results, undo refs, apply errors, and check verifier output are
|
|
397
|
-
validated from own fields only; prototype-inherited fields are ignored before
|
|
398
|
-
they can become run proof. Apply-result objects and verifier check objects must
|
|
399
|
-
be plain record-shaped payloads, not arrays with attached fields.
|
|
400
|
-
Adapter-returned ops and verifier proof must be data properties, including
|
|
401
|
-
non-enumerable guard fields such as `kind`. Runtime evidence arrays must contain
|
|
402
|
-
own enumerable data entries; holes, non-enumerable entries, and accessors are
|
|
403
|
-
rejected before any getter can run during validation, cloning, or preview/apply
|
|
404
|
-
comparison.
|
|
405
|
-
Readback checks attach proof to passed checks, such as
|
|
406
|
-
`{ source: "readback", value: 12 }` or
|
|
407
|
-
`{ source: "readback", formula: "input*factor" }`.
|
|
408
|
-
Readback proof objects, check objects, expectations, and formula labels must be
|
|
409
|
-
record-shaped payloads, not arrays with attached fields.
|
|
410
|
-
Formula readback proof is parsed with `@bilig/formula` and stored in canonical
|
|
411
|
-
no-leading-`=` form, so harmless runtime differences such as a leading equals
|
|
412
|
-
sign, whitespace, or redundant parentheses do not make proof fail.
|
|
413
|
-
Each requested target may appear only once in runtime readbacks; duplicate
|
|
414
|
-
targets fail with `readback_duplicate` instead of being silently collapsed.
|
|
415
|
-
Generic check verifiers may only change `status` or add JSON-safe `proof`; they
|
|
416
|
-
cannot rewrite the check contract.
|
|
417
|
-
Consumer `checks()` return values are treated as model-output data too: returned
|
|
418
|
-
check arrays must contain own enumerable data entries, and returned check fields
|
|
419
|
-
must be own data properties. Accessor-backed or sparse returned checks fail
|
|
420
|
-
planning without running hidden getters.
|
|
421
|
-
If runtime apply succeeds but readback or check proof fails, the failed result
|
|
422
|
-
still carries `changed` and `undo` when the adapter returned applied ops or undo
|
|
423
|
-
metadata. A failed result before apply, or a failed apply that reports
|
|
424
|
-
`appliedOps: []` without undo metadata, uses `changed: []`.
|
|
425
|
-
Returned run results are frozen before they cross the public boundary, so an
|
|
426
|
-
agent can inspect `status`, `changed`, `checks`, `errors`, `apply`, `undo`, and
|
|
427
|
-
`unverified` without another actor mutating the proof underneath it.
|
|
428
|
-
|
|
429
|
-
The result is deliberately plain:
|
|
164
|
+
Use `runWorkbookPlan(planOrData, adapter, { strict: true })` when an agent needs
|
|
165
|
+
production proof. Strict mode requires:
|
|
166
|
+
|
|
167
|
+
- a valid plan before mutation
|
|
168
|
+
- at least one planned check before mutating actions
|
|
169
|
+
- adapter capabilities for the planned work
|
|
170
|
+
- plan id proof
|
|
171
|
+
- base and applied revision proof
|
|
172
|
+
- apply proof with no unverified apply facts
|
|
173
|
+
- concrete applied ops for every planned command
|
|
174
|
+
- command receipts bound to the planned command digests
|
|
175
|
+
- resolved-ref proof for ref-targeting commands
|
|
176
|
+
- proof on every passed check
|
|
177
|
+
|
|
178
|
+
Runtime authors can run the same contract with `checkWorkbookRunAdapter` or
|
|
179
|
+
`assertWorkbookRunAdapter` from `@bilig/workbook/testing`.
|
|
180
|
+
|
|
181
|
+
The returned `WorkbookRunResult` is intentionally plain:
|
|
430
182
|
|
|
431
183
|
```ts
|
|
432
184
|
type WorkbookRunResult =
|
|
@@ -449,104 +201,58 @@ type WorkbookRunResult =
|
|
|
449
201
|
}
|
|
450
202
|
```
|
|
451
203
|
|
|
452
|
-
##
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
`
|
|
478
|
-
`
|
|
479
|
-
`
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
accepted bundle and applied revision, so later agents can inspect the generic
|
|
488
|
-
proof without replaying human spreadsheet UI state.
|
|
489
|
-
|
|
490
|
-
After a runtime has previewed or applied a bundle, call
|
|
491
|
-
`workbookCommandResultForReceipts(bundle, receipts, { revision, undo })` to turn
|
|
492
|
-
receipt evidence into the same boring public result shape. The helper validates
|
|
493
|
-
receipt count and request identity, aggregates changed ranges, reports
|
|
494
|
-
preview/apply `matched` proof when ops are present, and carries undo metadata
|
|
495
|
-
without requiring `@bilig/core`. If a command declared `touchedRanges`, receipt
|
|
496
|
-
`changedRanges` must stay inside that declared scope. Use
|
|
497
|
-
`checkWorkbookCommandResult(data)` or
|
|
498
|
-
`normalizeWorkbookCommandResult(data)` before trusting a transported result. An
|
|
499
|
-
`"accepted"` result is only the pre-runtime handoff acknowledgement: it must not
|
|
500
|
-
carry settled proof fields such as receipts, changed ranges, revision, undo, or
|
|
501
|
-
errors. Those fields are valid only on receipt-backed runtime result statuses.
|
|
502
|
-
Command-result check verdicts are frozen.
|
|
503
|
-
Use `checkWorkbookCommandResultForBundle(bundle, data)` when a stored or
|
|
504
|
-
transported result must be mechanically checked against the bundle it claims to
|
|
505
|
-
settle. It compares bundle id, target revision, idempotency key, command count,
|
|
506
|
-
touched ranges, request or low-level-op receipt identity, receipt changed-range
|
|
507
|
-
scope, and final applied revision. It also recomputes result `status`,
|
|
508
|
-
`matched`, `changedRanges`, and `errors` from receipts, so an adapter cannot
|
|
509
|
-
smuggle a hand-edited summary past the public proof boundary. For low-level `op`
|
|
510
|
-
commands, use
|
|
511
|
-
`workbookOpCommandReceiptIdentity` or `workbookOpCommandReceipt` so adapters do
|
|
512
|
-
not invent receipt ids.
|
|
513
|
-
|
|
514
|
-
Use `checkWorkbookCommandReceipt(data)` before trusting runtime command evidence.
|
|
515
|
-
It returns the same boring `{ status, issues }` shape for receipt fields such as
|
|
516
|
-
`status`, `featureId`, `commandId`, `previewOps`, `appliedOps`, `undo`,
|
|
517
|
-
`changedRanges`, `proof`, `metadata`, and `errors`. Feature manifests, command
|
|
518
|
-
requests, and command receipts are validated from own payload fields only;
|
|
519
|
-
prototype-inherited fields are ignored. Receipt verdicts are frozen. Receipt ops are frozen after
|
|
520
|
-
normalization, changed ranges are canonicalized through the same workbook range
|
|
521
|
-
normalizer used by command scopes, and manifest or receipt arrays must contain
|
|
522
|
-
own enumerable data entries. Holes, non-enumerable entries, invalid range
|
|
523
|
-
addresses, and accessor-backed ops, undo ops, ranges, or errors are rejected
|
|
524
|
-
before any getter can run.
|
|
525
|
-
Receipt statuses are semantic: `previewed` cannot include applied proof,
|
|
526
|
-
`applied` cannot include errors and must carry applied evidence, `rejected`
|
|
527
|
-
cannot claim changed workbook proof, and `noop` cannot claim changed ranges or
|
|
528
|
-
ops.
|
|
529
|
-
`workbookCommandReceiptOpsMatch` uses canonical op equality instead of object
|
|
530
|
-
property order and refuses accessor-backed proof data.
|
|
204
|
+
## Data Boundaries
|
|
205
|
+
|
|
206
|
+
Everything that crosses an agent/runtime boundary is inspectable data:
|
|
207
|
+
|
|
208
|
+
- `describeModel`, `describePlan`, `describePlanResult`, and
|
|
209
|
+
`describeRunResult` return JSON-safe descriptions.
|
|
210
|
+
- `toPlanData(plan)` emits executable plan data for transport.
|
|
211
|
+
- `checkPlanData(data)` reports path-based transport issues before hydration.
|
|
212
|
+
- `hydratePlanData(data)` restores frozen refs and helper methods locally.
|
|
213
|
+
- `verifyPlan`, `verifyPlanData`, and `verifyModel` return frozen verdicts.
|
|
214
|
+
- `checkWorkbookReadbackProof(data)` validates transported readback proof.
|
|
215
|
+
- `workbookJsonSchemas`, `workbookJsonSchemaHashes`, and `fixtures/` publish
|
|
216
|
+
checked plan, runtime-requirements, command, run-result, and readback artifacts
|
|
217
|
+
for non-TypeScript consumers.
|
|
218
|
+
|
|
219
|
+
Public validators read own data properties and reject malformed, sparse,
|
|
220
|
+
accessor-backed, or custom-prototype payloads before hidden consumer code can
|
|
221
|
+
run. Public results are frozen before they cross the package boundary.
|
|
222
|
+
|
|
223
|
+
## Feature Commands
|
|
224
|
+
|
|
225
|
+
Runtimes can expose workbook extensions with the same data-first contract:
|
|
226
|
+
|
|
227
|
+
- `defineWorkbookFeaturePlugin`
|
|
228
|
+
- `checkWorkbookFeaturePlugin`
|
|
229
|
+
- `checkWorkbookCommandRequest`
|
|
230
|
+
- `checkWorkbookCommandBundle`
|
|
231
|
+
- `workbookCommandResultForReceipts`
|
|
232
|
+
- `checkWorkbookCommandResult`
|
|
233
|
+
- `checkWorkbookCommandResultForBundle`
|
|
234
|
+
- `checkWorkbookCommandReceipt`
|
|
235
|
+
|
|
236
|
+
Import these from `@bilig/workbook/features` when building runtime-owned
|
|
237
|
+
extensions. Ordinary models should prefer `writeFormula`, `writeValue`,
|
|
238
|
+
`format`, `clear`, and checks.
|
|
531
239
|
|
|
532
240
|
## Low-Level Ops
|
|
533
241
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
242
|
+
The existing workbook operation language remains public:
|
|
243
|
+
|
|
244
|
+
- `WorkbookOp`
|
|
245
|
+
- `WorkbookTxn`
|
|
246
|
+
- `EngineOp`
|
|
247
|
+
- `EngineOpBatch`
|
|
248
|
+
- guards such as `isEngineOpBatch`
|
|
538
249
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
Low-level op guards accept plain own-field payloads only. Prototype-inherited
|
|
543
|
-
op fields, nested ranges, and batch clocks are ignored so transported ops cannot
|
|
544
|
-
smuggle proof through object prototypes. Accessor-backed required fields,
|
|
545
|
-
nested fields, and op-array entries are rejected from descriptors without
|
|
546
|
-
running getters.
|
|
250
|
+
Most models should not start there. Use `workbook.addOp(op, { target, message })`
|
|
251
|
+
inside an action only when the generic action helpers cannot express the
|
|
252
|
+
required workbook intent.
|
|
547
253
|
|
|
548
254
|
## Example
|
|
549
255
|
|
|
550
256
|
See [examples/workbook-agent-model](../../examples/workbook-agent-model) for a
|
|
551
|
-
generic model that plans, verifies, describes, runs, and prints proof
|
|
552
|
-
depending on a hardcoded business model.
|
|
257
|
+
generic model that plans, verifies, describes, transports, runs, and prints proof
|
|
258
|
+
without depending on a hardcoded business model.
|