@openengio/cli 0.33.0 → 0.37.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openengio/cli",
3
- "version": "0.33.0",
3
+ "version": "0.37.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "engines": {
@@ -5,9 +5,9 @@ description: Use when a person wants an object type's drawer (its object view) o
5
5
 
6
6
  # Build an object view or an App view
7
7
 
8
- A type carries up to two views in `presentationBindings.views`: an **object view**, which lays out the drawer of
9
- one object, and an **App view**, which lays out the type's page. Both are display only: they show data and take
10
- page controls, and they never act. A view is built only from the platform's view catalogue. Read the catalogue
8
+ A type can carry three views in `presentationBindings.views`: an **object view**, which lays out the details panel
9
+ for one engineering record, an **App view**, which lays out the type's collection page, and a **card view**, a compact record summary. They show data. Object, App and page
10
+ views take page controls, and a **Button** in them can run a verb or set properties; a card view takes neither. A view is built only from the platform's view catalogue. Read the catalogue
11
11
  reference before step 3: the platform's agent loads it as the skill `author-views`, generated from the
12
12
  catalogue the platform validates against. The CLI does not yet ship that generated reference. With `openeng`,
13
13
  use this guide's examples and `openeng help types draft revise` for the wire shape, then validate the change
@@ -47,7 +47,7 @@ For each question, choose the components that answer it. Use the reference for w
47
47
  | group or hide detail | `Section`, `Tabs` and `TabPanel`, `Disclosure`, `Card`, `Grid`, `Stack` | the same |
48
48
  | link to an object | `Link` | `Link` |
49
49
 
50
- The root is `ObjectBody` for an object view and `AppBody` for an App view, and appears nowhere else.
50
+ The root is `ObjectBody` (the object-view container) for an object view and `AppBody` (the collection-page container) for an App view, and appears nowhere else.
51
51
 
52
52
  ## 4. Bind the data
53
53
 
@@ -79,7 +79,7 @@ Check: the model's convention is written down, and every edge follows it.
79
79
  `build-ui` skill).
80
80
  - A **named view** (`structureDeclaration.views`, each `{ key, label, steps }`) is a saved tree: one or
81
81
  two edge steps. A two-step view passes through an intermediate object, which is left out of the tree
82
- and may lend properties to the row (`decoration`); a part under its assembly through a BOM line, with
82
+ and may lend properties to the row (`decoration`, displayed properties from that intermediate record); a part under its assembly through a BOM line, with
83
83
  the line's quantity on the row.
84
84
  - **Declaring any named view replaces the web's relationship picker with a picker of those views alone.**
85
85
  When you add a view, declare the tree people use most as a view too, first, because the first view is
@@ -115,7 +115,7 @@ then appears once at each placement, and its ancestry depends on the selected tr
115
115
  drawer; an **App view** (`.app`, root `AppBody`) lays out the type's page. Only components the view
116
116
  catalogue admits may appear, each with the props it takes.
117
117
 
118
- An **App** is an organisation entity with its own pages and drafts, linked by `openeng link app`.
118
+ An **App** is an organisation-owned application definition with its own pages and drafts, linked by `openeng link app`.
119
119
  An **App view** is a type's collection content in `presentationBindings.views.app`, root `AppBody`,
120
120
  and cannot be linked by `link app`.
121
121
 
@@ -186,8 +186,12 @@ An enum's `members` is a list of strings or finite numbers. A published member c
186
186
 
187
187
  ### number
188
188
 
189
+ A number or integer may declare a unit under schema language version `4`. The value is still
190
+ a number, displayed with that unit. Publication refuses unknown symbols (`unknown-unit`), and
191
+ a later version may add a unit but cannot change or remove it (`changed-unit`).
192
+
189
193
  ```json
190
- {"kind": "number"}
194
+ {"kind": "number", "unit": "kg"}
191
195
  ```
192
196
 
193
197
  ### integer
@@ -224,6 +228,9 @@ An instant, under schema language version `2`.
224
228
 
225
229
  ### attachment
226
230
 
231
+ Create the object first, then stage and save its attachment. Creation with a file is refused
232
+ as `invalid-properties` with `attachment-requires-object` at each offending property.
233
+
227
234
  A file descriptor on a top-level object property, under schema language version `3`. The kind is
228
235
  refused inside object or array properties and in edge and verb schemas. `accept` lists admitted
229
236
  classes: adding a class is compatible; removing one or changing the property's kind is refused.
@@ -251,6 +258,21 @@ one property's bytes.
251
258
  }
252
259
  ```
253
260
 
261
+ ### bound
262
+
263
+ A quantitative constraint on a top-level object property, or an entry in a top-level array of
264
+ bounds, under schema language version `4`. A value such as
265
+ `{"over":"each","quantity":"mass","comparison":"<=","value":100,"unit":"kg"}` compares
266
+ each linked object's mass against 100 kg. `sum`, `min`, `max` and `count` aggregate the linked
267
+ values. A limit may instead be `{ "property": "allocation" }`, read from this object's own
268
+ numeric property. `within` requires a non-negative `tolerance`; other comparisons take none.
269
+ Compatible units are converted for comparison; incompatible units answer `unit-mismatch`.
270
+ Bounds answer independently of review: clearing a suspect link does not make an `out` bound `in`.
271
+
272
+ ```json
273
+ {"kind": "bound"}
274
+ ```
275
+
254
276
  ## 9. Examples
255
277
 
256
278
  These are small type documents to adapt and validate in a change set before accepting it.
@@ -270,7 +292,7 @@ These are small type documents to adapt and validate in a change set before acce
270
292
  ### Example: template verb with its result contract
271
293
 
272
294
  ```json
273
- {"typeCategory":"verb","typeKey":"create-task","version":1,"displayName":"Create task","description":null,"allowedSubjectTypes":"none","inputSchema":{"kind":"object","properties":{"name":{"kind":"string"}},"required":["name"]},"resultSchema":{"kind":"null"},"schemaLanguageVersion":"1","template":{"operations":[{"kind":"create-object","typeKey":"task","properties":{"name":{"slot":"input","key":"name"}}}]}}
295
+ {"typeCategory":"verb","typeKey":"create-task","version":1,"displayName":"Create task","description":null,"allowedSubjectTypes":{"kind":"none"},"inputSchema":{"kind":"object","properties":{"name":{"kind":"string"}},"required":["name"]},"resultSchema":{"kind":"null"},"schemaLanguageVersion":"1","template":{"operations":[{"kind":"create-object","typeKey":"task","properties":{"name":{"slot":"input","key":"name"}}}]}}
274
296
  ```
275
297
 
276
298
  A minimal object type and a structural edge, every key at version 1:
@@ -107,8 +107,7 @@ cares about; do not explain a primitive in isolation.
107
107
  - C4: open a record's history, comment and subscribe; use `objects-sdk previewDelete` before
108
108
  any deletion, and read branch history and `admin-sdk listAudit`.
109
109
  - C5: explain that the organisation's agent model is chosen in the web app under **Admin**, **Agent model**.
110
- Run `openeng link organisation-page agent-model` and open or share the returned link. The CLI
111
- has no read of the selected model; do not claim to have read it. Show the project's `ceiling show`. The person uses
110
+ Run `openeng link organisation-page agent-model` and open or share the returned link. Run `openeng admin-sdk readModelConfigurationStatus` to read the selected model; this read needs `administer agents` on the organisation. Show the project's `ceiling show`. The person uses
112
111
  "Open agent", approves its plan, inspects the branch diff, submits and merges. Read the audit
113
112
  naming the person and run; show the agent refused on protected main.
114
113
  - C6: use `locks set --lock frozen` on a released part, show an edit refused, create its successor
@@ -128,7 +127,7 @@ Invite an action that matters, then check its result with a read. Keep accepted,
128
127
  published and seen in the app distinct. Drive through the CLI; the person operates the app.
129
128
 
130
129
  The person enters Onshape keys themselves at `openeng connector set-credential`'s prompt;
131
- never ask for keys in conversation or type them. Mirrored objects are owned by the connector.
130
+ never ask for keys in conversation or type them. Mirrored objects can be changed only by the connector that imports them.
132
131
  For OAuth, read the published client contract and `openeng help admin-sdk registerClient`.
133
132
  Register a public client with a `http://127.0.0.1:<port>/callback` redirect; use authorization code
134
133
  with PKCE. Keep the local app read-only unless asked for more; it never sees their password.
@@ -5,7 +5,7 @@ description: Use when a person wants types for a use case their organisation's c
5
5
 
6
6
  # Design the types for a new use case
7
7
 
8
- Work through the steps in order. Do not skip a stop point: at each one, show the person what you
8
+ Work through the steps in order. A catalogue is the organisation's shared set of object and relationship definitions. A change set is the saved draft of proposed definition changes. Do not skip a stop point: at each one, show the person what you
9
9
  have and wait for their agreement. Ask at most three questions at a time, each with lettered options
10
10
  and your recommendation. Draft nothing in a change set before step 7. Read `openeng skill conventions` before
11
11
  step 3; it holds the rules every step below relies on.
@@ -21,7 +21,7 @@ step 3; it holds the rules every step below relies on.
21
21
  | open a change set | `open_change_set` | `openeng types draft open` |
22
22
  | save the changed types | `revise_change_set` | `openeng types draft revise --change-set <id> --revision <token> --from <file> [--rail-groups <json>]` |
23
23
  | validate | `validate_change_set` | `openeng types draft validate --change-set <id> --revision <token>` (exit 4 with violations) |
24
- | try a sample against a draft type | `try_instance` | none yet; validate, and after acceptance write one object on a throwaway branch |
24
+ | try a sample against a draft type | `try_instance` | `openeng types draft try`; checks a sample without an engineering write |
25
25
  | publish | never: the person publishes | `openeng types draft accept` only after the person says so, for that change set |
26
26
  | search the web | `web_search`, `web_fetch` | your own tools, under the same rule: never put anything read from the platform into a query or an address |
27
27
 
@@ -21,6 +21,22 @@ their own. Before you send a generated command (`objects-sdk`, `branches-sdk` an
21
21
  `<module> <method>` commands), run `openeng help <module> <method>`. It prints the fields, the kinds a
22
22
  field may take, the selector keys and one example input, and needs no sign-in.
23
23
 
24
+ ## Read a route's policy
25
+
26
+ Generated route help prints `actors` (the caller categories allowed) and `step-up` (whether user confirmation is required) from the route table's current `policy` (access rules).
27
+ The policy is `{ none: true }` for no access-token requirement, or an `actors` map whose keys name
28
+ admitted classes and whose values state each class's step-up. `person` is the person's authority;
29
+ in-app agent names are `agent:explore`, `agent:apply` and `agent:types`. Application actors use
30
+ `app:client` or `app:hosted`, and service authority uses `service`. These are actor labels;
31
+ a CLI session in agent mode still acts as `person`.
32
+
33
+ A step-up value is `none`, `person-present` (requires the signed-in user's confirmation), or `{ personPresentWhen: <predicateName> }` (requires confirmation when a condition is met). Help
34
+ names the predicate and its condition, including `unlocks` (the condition for removing a lock) when a lock is set to `"none"`.
35
+ Read the generated lines for the route you need; this skill keeps no separate admission list.
36
+ A person's own live web session is never challenged. An agent-mode CLI call (a session configured to require confirmation for sensitive actions) on an action requiring confirmation
37
+ meets the challenge and waits for its person, as described below. In-app agent classes are omitted
38
+ from every marked policy in this release; confirmation cannot grant them admission.
39
+
24
40
  ## Explain each step
25
41
 
26
42
  When guiding a person, say what you intend to learn or change, give the command, then report what it
@@ -47,6 +63,9 @@ that step; do not construct a page address yourself. For example:
47
63
 
48
64
  ## Attachments
49
65
 
66
+ Create the object first, then stage and save its attachment. Creation with a file is refused
67
+ as `invalid-properties` with `attachment-requires-object` at each offending property.
68
+
50
69
  For a top-level object property declared with kind `attachment`, use
51
70
  `openeng attachment add <object> <property> <file> --project <id> --ref <ref>` to stage a file and
52
71
  save its descriptor, `openeng attachment list <object> --project <id> --ref <ref>` to read its
@@ -54,18 +73,77 @@ attachment properties, and `openeng attachment get <object> <property> [--out <p
54
73
  project and ref flags to download it. The `get` command uses the descriptor's file name when `--out`
55
74
  is omitted. The accepted classes and file-size limit are in `openeng skill conventions`.
56
75
 
76
+ ## Link review and impact
77
+
78
+ Read `openeng links status <object> --project <id> --ref <ref>` before reviewing a tracked
79
+ link. Review states are `cleared` (reviewed against the current upstream), `suspect` (significant
80
+ upstream content changed), `unreviewed` (never cleared), `not-visible` (the upstream cannot be
81
+ read) and `too-many-links` (the chain exceeds its bound). Bounds have their own states: `in`,
82
+ `out`, `none`, `no-value`, `unit-mismatch` and `not-visible`; clearing does not change them.
83
+ Aggregates also show coverage and hidden or missing counts. Numeric output shows its unit.
84
+
85
+ After reviewing the upstream, run `openeng links clear <link> --version <upstreamVersion>
86
+ --project <id> --ref <ref>`. Take the opaque version from the status answer. For an atomic batch,
87
+ list up to 100 link ids and repeat `--version` once per link in the same order. On
88
+ `upstream-changed`, read status and review before sending its new version; do not replace the
89
+ precondition blindly. `upstream-not-readable` requires upstream read access. There is no
90
+ organisation clearing setting: the edge's write rule decides who may clear. Read the generated route
91
+ help for the actor classes admitted to clearing.
92
+ The object agent has no clearing tool; clear through this CLI or the SDK. Recover an unknown
93
+ outcome by correlation before retrying.
94
+
95
+ Use `openeng branches impact <ref> --base <base> --project <id>` to review changes against
96
+ the merge base: review, bounds and aggregate changes, downstream reach to depth three and
97
+ hidden counts. Added and removed links are marked. `head-moved` requires reading again;
98
+ `over-bound` refuses the entire read. Add `--json` for each complete answer.
99
+
100
+ ## Hosted apps
101
+
102
+ A hosted app is a React bundle that runs inside a project, in a sandbox, with the viewer's authority.
103
+ Export a component that takes `{ client }` and start it by calling the runtime's
104
+ `globalThis.__oe2HostedApp.mount(App)` as the bundle's last statement (the `@openengio/hosted-app`
105
+ package that wraps this call is not published yet). Publish the built bundle with
106
+ `openeng hosted-app publish <bundle> --project <id> --key <app key>`; it creates the app when the
107
+ project has none under that key, and prints the version and its SHA-256. If the app holds the
108
+ reduced isolation permission, output carries a warning when its grants can be read: read it to the person and do not hide it. If grants cannot be read, output says the permission is unknown.
109
+ `openeng hosted-app list --project <id>` lists the apps, `openeng hosted-app versions <app key>
110
+ --project <id>` lists an app's versions, and `openeng hosted-app revoke <app key | app id | version id>
111
+ --project <id>` revokes a version (an id starting `hav_`) or the whole app by its key or `app_` id. Revoke only when the
112
+ person asks. Hosted apps run only in Google Chrome.
113
+
57
114
  ## Rules that hold for every command
58
115
 
59
116
  - Add `--json` when you read the answer yourself. It prints one JSON value on standard output.
60
- - Exit code 0 is success. Any other exit code is a refusal or a failure, and its message says what
117
+ - Exit code 0 is success. Any other exit code is a refusal (a rejected operation with a reason) or a failure, and its message says what
61
118
  to do. Read it; do not retry the same command unchanged.
62
119
  - When you report a refusal to the person, quote its `reference:` line (the `reference` field under
63
120
  `--json`) exactly. The line is how the platform's operators find the request. A refusal with no
64
121
  such line was built by `openeng` itself, or the host sent no id with it.
65
122
  - A refusal of a field names the field, such as `input.correlation`, and the kinds it may take.
66
123
  Fix that field and send the command again.
124
+ - A command that the platform holds to the person's own confirmation prints an address, then waits.
125
+ Tell the person to open that address in their browser and confirm; the command carries on by itself
126
+ once they do, and prints nothing from the confirmation. A timeout reports that the action was refused
127
+ because nobody confirmed in time and exits non-zero, with no write. Other poll refusals retain their
128
+ actual meaning. Read the refusal before deciding whether to ask the person to try again. A refusal
129
+ `step-up-required` (confirmation needed) or `step-up-mismatch` (confirmation did not match this action) that still reaches you
130
+ means that CLI session still needs confirmation for that call. A different CLI session of the
131
+ same person cannot collect or use its proof. In-app agent tokens are refused on every marked action,
132
+ even with a proof, so do not retry the command or look for another way to make the
133
+ change. Tell the person which action was refused and ask them to make it themselves. A refusal
134
+ `step-up-capacity` means the person already has the most confirmations waiting; ask them to
135
+ clear those first.
136
+ - CLI sessions start in agent mode. The server stores channel and mode; local `whoami` output is
137
+ identity information, not evidence of human mode. Use `openeng session status` for the server's
138
+ channel, mode and sign-in time. A person working at the terminal can deliberately run
139
+ `openeng session human`, confirm once in their browser, and stop further prompts for the life of
140
+ that CLI session. The command prints the stored mode; repeating it is a no-op. A fresh CLI login
141
+ starts in agent mode. Only request human mode when the person explicitly asks for it. An unknown
142
+ session becomes CLI/agent on confirmation and challenges again
143
+ on its next marked action. A browser's own unknown session must sign in again, without a confirm
144
+ link or automatic replay.
67
145
  - `openeng help` lists every command. `openeng help <command words>` prints one command's help: what it
68
- does, an example and the shape of its output. `openeng help <group>` lists a group's commands.
146
+ does and an example. `openeng help <group>` lists a group's commands.
69
147
  `openeng --version` prints the published version.
70
148
  - `openeng` has no host built in. The production host is `https://api.openeng.io`: pass
71
149
  `--host https://api.openeng.io` on every command, or prefix it as
@@ -94,7 +172,7 @@ is omitted. The accepted classes and file-size limit are in `openeng skill conve
94
172
  5. Until you attach, these commands run without an organisation: `openeng login`, `openeng logout`,
95
173
  `openeng whoami`, `openeng help`, `openeng skill`, `openeng org list`, `openeng org attach <id>`,
96
174
  `openeng org create --name <name>`, and `openeng org current`. The generated command
97
- `openeng admin-sdk createOrganisation` also runs unattached. Other commands refuse with "not attached
175
+ `openeng admin-sdk createOrganisation`, `openeng session status`, and `openeng session human` also run unattached. Commands that need an organisation refuse with "not attached
98
176
  to an organisation" before they send anything.
99
177
  6. `openeng projects list --json`. Note each project's id and its namespace; later steps need both.
100
178
  7. `openeng types list --project <project id>` to see the project's published types, each with its
@@ -105,12 +183,12 @@ For a generic open-cycle gas turbine demonstration project, run `openeng demo se
105
183
  ### Which organisation you are in
106
184
 
107
185
  - `openeng org current` prints the organisation your session is attached to, or none.
108
- `openeng org detach` removes the attachment, and the commands refuse again until you attach.
186
+ `openeng org detach` removes the attachment; commands that need an organisation refuse until you attach again.
109
187
  - The CLI passes no scope for `openeng login`, `openeng logout`, `openeng whoami`, `openeng help`, `openeng skill`,
110
188
  `openeng org list`, `openeng org attach <id>`, `openeng org create --name <name>`, `openeng org current`,
111
- `openeng org detach`, and `openeng admin-sdk createOrganisation`. Other commands print their scope on
189
+ `openeng org detach`, `openeng admin-sdk createOrganisation`, `openeng session status`, and `openeng session human`. Other commands that need an organisation print their scope on
112
190
  standard error when the platform answers them, as
113
- `org: <name> (<id>)`, then `· project: <id>` and `· ref: <ref>` when you named them. Read it
191
+ `org: <name> (<id>)`, then `· project: <id>` and `· ref: <ref>` when named in `--selector`. Read it
114
192
  before you trust an answer.
115
193
  - With `--json`, the one value on standard output carries the same scope as a `scope` object:
116
194
  `{"organisation": {"id", "name"}, "project"?, "ref"?}`. An object value normally gains a `scope` key.
@@ -128,14 +206,16 @@ For a generic open-cycle gas turbine demonstration project, run `openeng demo se
128
206
  Edit a file, not the published types directly. The change is a draft that is checked, reviewed and
129
207
  then accepted.
130
208
 
131
- If `openeng types list` says `no published types`, start the type file from the `changes` map in the
132
- example input printed by `openeng help ontology-sdk reviseChangeSet`. Read `openeng help types draft revise`
133
- to understand each part, then design the model with the person before you draft it.
209
+ If `openeng types list` says `no published types`, use the example type documents in
210
+ `openeng skill conventions` to start the type file. Put each type document under its type key, because
211
+ `draft.json` is a map keyed by type key and a bare document is refused. Read `openeng help types draft revise` to
212
+ understand each part, then design the model with the person before you draft it.
134
213
 
135
214
  1. If the project has published types, run `openeng types export --project <project id> > draft.json`;
136
215
  it writes them as one JSON object keyed by type key, each at the next version, ready to send
137
- with revise. If it has no published types, create `draft.json` from the `changes` map in the
138
- example input printed by `openeng help ontology-sdk reviseChangeSet`.
216
+ with revise. If it has no published types, create `draft.json` from an example type document in
217
+ `openeng skill conventions`, putting the type document under its type key: the headed examples there
218
+ are bare documents, and one pasted as it stands is refused.
139
219
  A new object type needs `presentationBindings.typeIcon`; read the existing types' icons in the
140
220
  export and choose a relevant glyph that no other type uses.
141
221
  2. Make `draft.json` hold only the types you change: delete every other key, and keep each type you
@@ -160,7 +240,10 @@ to understand each part, then design the model with the person before you draft
160
240
  `openeng types list`.
161
241
 
162
242
  Property kinds are `null`, `boolean`, `string`, `number`, `integer`, `person`, `enum`, `array`,
163
- `object`, `datetime` and `attachment`. Use `datetime` for an instant. A value is an RFC 3339 date-time
243
+ `object`, `datetime`, `attachment` and `bound`. Under language version `4`, numeric properties may
244
+ declare a `unit`, such as `kg`; publication refuses an unknown symbol (`unknown-unit`) or a later
245
+ change or removal (`changed-unit`). A `bound` is a top-level object property, or a top-level array
246
+ of bounds, under version `4`. See `openeng skill conventions` for its shape. Use `datetime` for an instant. A value is an RFC 3339 date-time
164
247
  with an explicit offset and zero to three fraction digits, such as `2026-10-19T22:30:00+01:00` or
165
248
  `2026-10-19T21:30:00Z`; a value with no offset, an impossible date or time, or four or more fraction
166
249
  digits is refused. The platform stores it as `YYYY-MM-DDTHH:MM:SS.sssZ`, the same instant in UTC.
@@ -209,12 +292,52 @@ project's `main`. Use a branch and review when a rule protects the branch or the
209
292
  5. `openeng objects-sdk executeVerb` runs a verb a type defines. `openeng objects-sdk discoverVerbs` lists
210
293
  the verbs available.
211
294
  6. When using a branch for review, `openeng branches-sdk submitProposal` sends it for review. It
212
- names the branch by its `name` alone, the part of the full branch name after the slash.
295
+ names the branch by its `name` alone, the part of the full branch name after the slash. The input
296
+ takes an optional `target`: `main`, a writable organisation ref or a project branch; omission
297
+ targets `main`. An apply run submits only its approved plan's ref.
298
+ 7. A person approves with `openeng branches-sdk approveProposal`, sending `proposalId` and, as
299
+ `headHash`, the `atHash` of the `readBranchDiff` they read. An approval from a CLI session in agent mode is confirmed
300
+ on the web. A moved head requires reading and reviewing again. An agent proposes and never approves.
301
+
302
+ ### Draft and comment routes
303
+
304
+ The Objects SDK transport also exposes `acquireDraft`, `saveDraft`, `promoteDraft`, `releaseDraft`,
305
+ `discardDraft`, `readDraftLock` and `breakDraftLock`. Read each request with
306
+ `openeng help objects-sdk <method>`. Draft methods take the selected project and ref plus an
307
+ `objectId`; `saveDraft` also takes the `draftHash` last read, `blocks` keyed by identifiers the
308
+ draft already holds, and `added`, a list of new blocks without identifiers; it answers the
309
+ identifiers the server minted for them in `minted`.
310
+ `openeng objects-sdk acquireDraft` starts a draft of the object's body and answers its blocks and
311
+ `draftHash`; `openeng objects-sdk promoteDraft` publishes the draft as the body with the
312
+ `draftHash` last read. If the body already equals the draft, promotion makes no commit; `body-changed` means it moved since the draft was acquired. Each takes `--selector` and `--input` as JSON, as the other routes here do. A save renews
313
+ the five-minute lock. Release only releases an
314
+ unchanged draft; discard removes the holder's draft, while breaking a lock leaves its draft text
315
+ in place and is a project-administrator action. `readDraftLock` reports the holder and expiry or
316
+ that no lock is live, never the draft contents.
317
+
318
+ A draft write blocked by a rule answers `protected`, with the same optional
319
+ `protection: { ref, patterns }` as a property save. Only readable patterns appear. Make the change
320
+ on another branch and merge it; a caller without write access receives the ordinary denial.
321
+
322
+ Object history (`openeng objects-sdk readHistory`) and a branch comparison
323
+ (`openeng branches-sdk readBranchDiff`) carry a `bodyChanges` list on each version or changed object:
324
+ one entry per body block that differs, `{ blockId, kind, before, after }`, with `kind` one of `added`,
325
+ `removed`, `changed` or `moved`, and only the block text. Read it to describe a body change; the
326
+ property fields do not show one.
327
+
328
+ `breakDraftLock` and `restoreDraft` require a person token and use `objects.draftAdmin`. No client
329
+ scope or run client holds this capability. `restoreDraft` takes `trashId` and `newRefName` and
330
+ restores a draft from the trash of a disposed branch onto a new ref.
331
+
332
+ `setCommentResolved` takes `commentId` and `resolved` and is for resolving or reopening a comment.
333
+ `addComment` takes the ordinary comment fields and an optional anchor naming the quoted block and
334
+ span. It admits people and hosted apps. Resolving a comment is a person action. The route's refusal is authoritative for required capability
335
+ and admitted caller kinds.
213
336
 
214
337
  If a verb name is unknown, use `openeng objects-sdk discoverVerbs` for the object and choose a
215
338
  listed verb; do not guess a verb key.
216
339
 
217
- If a command is refused, the refusal names the field and its allowed kinds. Run
340
+ A refusal may name the field it concerns, and `invalid-request` lists the kinds where the request schema allows it. Run
218
341
  `openeng help <module> <method>` again and compare.
219
342
 
220
343
  ### Read relationships back after a write
@@ -233,17 +356,29 @@ several objects; read its help before supplying input.
233
356
  ### Review object and relationship changes
234
357
 
235
358
  Run `openeng help branches-sdk diffBranches` for a live branch comparison, or
236
- `openeng help branches-sdk readBranchDiff` for a submitted proposal's reviewed comparison.
359
+ `openeng help branches-sdk readBranchDiff` for a proposal's comparison, at the branch's current head
360
+ while the proposal is pending, with `atHash` naming that head.
237
361
  Read both the object collection (`changes` for a live diff, `objects` for a proposal) and
238
- `edges`. One page holds at most 200 changes total; follow its cursor until it is null before
239
- describing the whole change. An edge's source and target carry object and project identifiers,
362
+ `edges`. Live diffs return `cursor`; proposal diffs return `continuation`. One page holds at most 200 changes total; follow the returned value until it is null before describing the whole change. An edge's source and target carry object and project identifiers,
240
363
  plus the edge's own properties before and after. An unreadable endpoint's identifiers do not
241
- grant access to its title, type or properties. A cursor from an older client is refused;
242
- start the comparison again with no cursor.
364
+ grant access to its title, type or properties. Any cursor that is not a current page boundary is refused; start the comparison again without it.
243
365
 
244
366
  ## Project branch rules
245
367
 
246
- `openeng branches-sdk disposeRef` is a writer's cleanup of a branch with no pending proposal.
368
+ `openeng branches-sdk disposeRef` lets a branch writer dispose when no pending proposal exists
369
+ and no matching rule restricts deletions, or when no rule matches even with a pending proposal.
370
+ Otherwise the caller must be on every matching rule's bypass list. A bypass member may dispose
371
+ with or without a proposal, including under restricted deletions, with write access to all affected
372
+ projects. Success discards the pending proposal after the engine disposal succeeds.
373
+
374
+ Merge and disposal admit people, services and client apps. Agent runs and hosted apps are refused
375
+ `token-kind-not-admitted`. With no rule matching the merge target, a writer of all affected projects
376
+ can merge, including a Contributor. A client of an Owner gets no role bypass from that person's role;
377
+ it needs an explicit client bypass entry.
378
+
379
+ When drafts block disposal it answers `ref-has-drafts` and lists readable drafts in writable
380
+ projects, by object and holder. Add `"deleteDrafts":true` to the input to consent: the drafts you may write move to the draft
381
+ trash, where a person who saved one can restore it.
247
382
 
248
383
  ### Resolve a merge conflict
249
384
 
@@ -253,26 +388,43 @@ When merge answers `merge-conflict`, read the conflicts with
253
388
  field, `base` is its value before either side changed it, `ours` is `main`, and `theirs` is the
254
389
  source branch's value. A value may be absent on a side. The read always compares the source with
255
390
  `main`, even if the merge targeted another branch, so it does not report conflicts from a merge
256
- whose target was not `main`. Reconcile the changes on the source branch, then submit a new merge
391
+ whose target was not `main`. A conflicting object also lists `blocks`: the body blocks both sides changed
392
+ differently, each `{ blockId, base, ours, theirs }` with the text of the common version, of `main` and of
393
+ the source branch (null where a side has no such block). Reconcile the changes on the source branch, then submit a new merge
257
394
  with the reviewed head; reading conflicts makes no changes.
258
395
 
259
- A project rule may protect `main` or branches under that project's identifier. A matching
260
- `merge-only` rule requires changes through a branch and merge. A `locked-rows-only` rule binds
261
- merge-only row locks on the matching branch while leaving unlocked rows direct.
262
-
263
- Rule management is the person's workflow: they must hold `administer projects` on the project
264
- and run these commands themselves. Never add or remove rules on their behalf, including to
265
- get past a refusal.
266
-
267
- 1. The person runs `openeng rules add --project <id> --pattern main --consequence merge-only`
268
- to protect the project's trunk. The answer includes the rule's identifier. Adding the same
269
- content again returns the existing rule.
270
- 2. `openeng rules list --project <id>` reads the visible rules, their identifiers, patterns and
271
- consequences; it needs `read` on the project.
272
- 3. To lift one rule, the person runs `openeng rules remove --project <id> --rule-id <id>` with
273
- the identifier from the list. An absent identifier or one from another project answers
274
- `not-found`. Removal is audited, as is addition, and takes effect on the next request.
275
- Other matching rules and row locks may still protect that branch's rows.
396
+ A rule has extent `ref` for every row on a matching ref or `rows` for its project's rows.
397
+ Project `ref` rules are `<project>/` and a glob; `rows` may also name `main`. In a glob `*` stops at
398
+ `/`, `**` is any characters, `/` included, `?` is one character other than `/`, and `[]` is a set
399
+ with no negation: `^` and `!` are refused. `<project>/**/x` does not match `<project>/x`. A glob is at most 255 characters.
400
+ `merge-only` requires merges, `locked-rows-only` binds merge-only row locks, and `open` allows
401
+ updates. Several matching rules all apply unless their bypass lists admit the caller.
402
+
403
+ Rule management is the person's workflow. They need `administer projects` on the owner.
404
+ Never add, update or remove rules on their behalf, including to get past a refusal.
405
+
406
+ 1. The person runs `openeng rules add --project <id> --extent rows --pattern main` to protect
407
+ their project's trunk rows. The answer includes the identifier and full settings.
408
+ 2. `openeng rules list --project <id>` reads visible rules and their settings; it needs `read`.
409
+ 3. `openeng rules update --project <id> --rule-id <id> [settings]` changes settings atomically.
410
+ Every update requires confirmation in an agent-mode session, stronger and weaker alike.
411
+ 4. `openeng rules remove --project <id> --rule-id <id>` removes that rule. An absent or other
412
+ owner's identifier answers `not-found`. Each change is audited and affects the next request.
413
+
414
+ Add and update accept `--consequence <open|merge-only|locked-rows-only>`,
415
+ `--require-proposal <true|false>`, `--required-approvals <0..10>`,
416
+ `--approver-min-role <contributor|maintainer|owner|null>`, `--restrict-deletions <true|false>`,
417
+ `--approvers '<JSON person-id array>'` and `--bypass '<JSON member array>'`.
418
+ Bypass members are `{"kind":"role","roleKey":"owner"}`, `{"kind":"person","personId":"<id>"}`,
419
+ `{"kind":"service","serviceIdentityId":"<id>"}` or `{"kind":"client","clientId":"<id>"}`.
420
+ A supplied array replaces the list; `[]` clears it. Omitted settings on update keep their values.
421
+ On add, defaults are merge-only, a required proposal, one approval, minimum Maintainer,
422
+ no named approvers and Owner/Maintainer bypass. Deletion restriction defaults to true for project
423
+ `ref` rules only; only those rules may enable it. Positive approvals need a proposal and either
424
+ a minimum role or a named approver. The server validates named members without revealing identities
425
+ outside the home. Refusals are `invalid-rule-pattern`, `invalid-rule-setting` and `unknown-rule-member`.
426
+ A repeated rule add returns the existing rule without changing it. Changing a rule’s consequence
427
+ to one another rule on that pattern already has is refused `duplicate-rule`; the rule stays unchanged.
276
428
 
277
429
  ## Organisation rules, branches and baselines, locks and agent ceilings
278
430
 
@@ -283,17 +435,17 @@ capability; read the help line before asking the person to seek permission.
283
435
 
284
436
  - The person uses the rules commands above with `--organisation` instead of `--project <id>`
285
437
  for organisation rules, for example
286
- `openeng rules add --organisation --pattern release-v1 --consequence merge-only`.
438
+ `openeng rules add --organisation --extent ref --pattern release-v1 --consequence merge-only`.
287
439
  Choose exactly one flag. `--organisation` takes no value and uses the attached organisation.
288
440
  `openeng rules list --organisation` reads the rules;
289
441
  `openeng rules remove --organisation --rule-id <id>` removes one by its identifier.
290
- Adding or removing needs `administer projects` in the attached organisation; listing needs `read`.
442
+ Adding or removing needs `administer projects` in the attached organisation; listing needs read on a project in the organisation.
291
443
  - `openeng org-refs list` reads organisation branches and baselines with their read-only state. The person creates
292
444
  a branch with `openeng org-refs create --name <name>` or a baseline by adding `--read-only`. A branch becomes a baseline with
293
445
  `openeng org-refs mark-read-only --name <name>`, or deletes a writable one with
294
446
  `openeng org-refs delete --name <name>`. Names are single segments, such as `release-v1`.
295
447
  Creating, deleting and marking need `administer projects` in the attached organisation;
296
- listing needs `read`.
448
+ listing needs read on a project in the organisation.
297
449
  - The person sets or lifts an object's lock with
298
450
  `openeng locks set --project <id> --ref <ref> --object <objectId> --lock <none|merge-only|frozen>`.
299
451
  `none` lifts it. The lock also applies to its existing structural child edges in the selected
@@ -313,9 +465,15 @@ When a command returns one of these rules, follow its action and do not repeat t
313
465
  different branch or baseline.
314
466
  - `protected`: a rule allows the record to change only through a merge from a branch. Make the
315
467
  change on a branch and merge it.
468
+ - `proposal-required`: submit the source branch for review against the merge target.
469
+ - `approvals-required`: read `approvals.counted` and `approvals.required` for the subject project.
470
+ Ask eligible reviewers to approve the source's current head; stale approvals do not count.
471
+ - `deletion-restricted`: ask a member of every matching rule's bypass list to dispose of the branch.
472
+ - `bypass-required`: a pending proposal and matching rules require bypass to dispose. Ask a member
473
+ of every matching rule's bypass list, or refuse the proposal first; deletion restrictions still apply.
316
474
  - `stale-source`: read a branch you can use and merge its current head. Optional merge `name`
317
475
  requires that bound branch's current head to equal `sourceHash`; it never selects a proposal.
318
- A successful merge into main closes every pending proposal in the project at that reviewed hash.
476
+ A successful merge closes only the source ref's pending proposal for that target.
319
477
  - `not-a-ref-head`: the branch has new commits since the review began. Reload the proposal to
320
478
  review its latest commit; the refusal does not identify the branch or its newer head.
321
479
  - `branch-needs-schema-update`: the branch's schema must be updated before writing. The
@@ -326,7 +484,7 @@ When a command returns one of these rules, follow its action and do not repeat t
326
484
  showing reads only the requester's records in the token organisation and needs no project read
327
485
  access. A branch whose name contains `/` cannot request or show a schema update today.
328
486
  - `organisation-not-ready`: the organisation's trunk is not ready. Try again shortly.
329
- - `read-only-ref`: nothing can be written or merged into this branch or baseline. Choose a writable branch.
487
+ - `read-only-ref`: this caller cannot write or merge into this ref; it does not mean nobody can. Choose a ref in your writable scope.
330
488
 
331
489
  ## 4. Link to a page
332
490
 
@@ -362,9 +520,11 @@ using the type key from the object read. Explore also reads its selected object
362
520
  ### Save an object set and link to its canvas
363
521
 
364
522
  1. Run `openeng help objects-sdk createObjectSet` and `openeng help objects-sdk readObjectSet`.
365
- 2. Query the objects you need with `openeng objects-sdk queryObjects --json`. Keep each object's
523
+ 2. Query the objects you need with `openeng objects-sdk queryObjects --selector <json> --input <json> --json`; read `openeng help objects-sdk queryObjects`
524
+ for the input. Keep each object's
366
525
  project with its identifier; one set may contain objects of several projects in your organisation.
367
526
  To combine two selections on the same ref, send `{ "kind": "set", "op": "difference", "left": { "kind": "objects", "typeKey": "..." }, "right": { "kind": "objects", "typeKey": "..." }, "limit": 100, "continuation": null }`. `op` may be `union`, `intersection` or `difference`. Each operand may have its own `projects`, `filters` and `steps`; operands cannot be nested set operations.
527
+ To select several object types in one paged query, use `typeKey: null` with a top-level `{ "kind": "type", "op": "in", "values": ["part", "system"] }` filter. The list holds 1 to 100 published type keys; combine it with a text filter to search those types. Follow the returned continuation without changing the selection.
368
528
  `aggregateObjects` also accepts `operation: "average"` with one numeric `property`; the result includes its mean and the count averaged, and omits the mean when that count is zero.
369
529
  3. Call `openeng objects-sdk createObjectSet` with a name and the selected addresses, following its
370
530
  help. Keep the returned set identifier and revision. Retrying with the same idempotency key
@@ -375,7 +535,7 @@ using the type key from the object read. Explore also reads its selected object
375
535
 
376
536
  Every kind with `--ref`, including `ontology` and `change-set`, takes `main` or
377
537
  `<projectId>/<branch>`, the branch name the platform returns. Baseline names are not accepted by `openeng link`. A bare branch name or change-set id is
378
- refused by `openeng link`. Before printing, the command reads the branch and the page's own subject;
538
+ refused by `openeng link`. Before printing, the command reads a `--ref` other than `main`, and the page's own subject where the kind has one;
379
539
  a subject it cannot find is a refusal with a reason and no printed address.
380
540
 
381
541
  An **App** is an organisation entity with its own pages and drafts, linked by `openeng link app`.
@@ -423,7 +583,7 @@ The order, from no connection to a first imported document:
423
583
 
424
584
  The connected system alone writes records of its owned types. A person's write is refused as
425
585
  `owned`. People put their own information in separate rows and link those rows to the mirrored
426
- records. The importer counts updates to mirrored properties as `overwritten`. If a mirrored
586
+ records. The importer counts an object as `overwritten` when a property the import changes was last modified by someone else; other changes count as `updated`. If a mirrored
427
587
  record is absent, the importer creates it with a new identifier and counts it as `created`.
428
588
 
429
589
  Refusals you will meet, with what each means and what to do:
@@ -441,8 +601,7 @@ Refusals you will meet, with what each means and what to do:
441
601
  permission.
442
602
  - `credential-not-valid`: Onshape did not accept the credential, and nothing was stored. The person
443
603
  checks the keys and runs `set-credential` again.
444
- - `connection-exists`: the organisation already has a live connection to this account on this
445
- stack. List the connections with `openeng admin-sdk listConnections` rather than creating another.
604
+ - `connection-exists`: the organisation already has a live connection for this stack and company. List the connections with `openeng admin-sdk listConnections` rather than creating another.
446
605
  - `connector-template-missing`: this deployment holds no type template for the connector's system.
447
606
  No remedy is in your reach; tell the person.
448
607
  - `change-set-open`: the organisation already has an open change set, so drafting the types
@@ -464,11 +623,10 @@ equal or higher project role, or the inviter lost the required standing. Sign-in
464
623
 
465
624
  Membership roles are `owner`, `maintainer`, `contributor` and `reader`. They grant, respectively:
466
625
 
467
- - `owner`: administer members, projects and service identities; write trunk, branches and protected
468
- rows; merge; and read.
469
- - `maintainer`: write trunk, branches and protected rows; merge; and read.
470
- - `contributor`: write branches and read. For example, a project contributor may edit on a branch
471
- and read the project, but does not gain merge or trunk-write permission.
626
+ - `owner`: administer members, projects and service identities; write refs and read.
627
+ - `maintainer`: write refs and read.
628
+ - `contributor`: write refs and read, including direct merges where no rule matches the target.
629
+ Matching rules and bypass entries decide how each ref may change.
472
630
  - `reader`: read.
473
631
 
474
632
  A membership can be scoped to an organisation or a project. An organisation role supplies its
@@ -116,6 +116,4 @@ Choose B for a team whose engineers read SysML or whose model will meet a SysML
116
116
 
117
117
  ## Not on the platform today
118
118
 
119
- - **Suspect links**: DOORS and Jama mark a link when its upstream end changes. Nothing does this yet; a
120
- team can review changes through a proposal's diff and an object's history.
121
119
  - **Coverage percentages** across levels: a count per question is a query; a roll-up is not built.
@@ -110,6 +110,6 @@ reached through a part or a plant.
110
110
 
111
111
  - **Effectivity** (a line valid from a date or a serial number): a date property is possible; nothing filters
112
112
  a structure by it.
113
- - **Mass change** of many lines, and a **cost roll-up** across a structure: a count per question is a query, a
114
- roll-up is not built.
113
+ - **Mass change** of many lines is not built. A **cost roll-up** across a structure is an Aggregate part
114
+ with a weighted sum over a repeat reach, which needs a numeric property on the edge, within its depth and type bounds.
115
115
  - **CAD geometry**: an object view can show an STL attachment (`STLViewer`); there is no live CAD link.