` with either a read-only value or a
small `
')
```
Integer inputs honour the underlying signed / unsigned width
(`uint8` → `min=0 max=255`, `int32` → `min=-2147483648 max=2147483647`,
etc.), so the browser does the first-pass validation for free.
Cross-instance references rendered as `ValueKey` become hyperlinks back
into `/documents/...`, which is what lets the user navigate the graph
of attachments by clicking through.
## The update round-trip
A successful field edit is a single `POST /update` with five form
fields: the three identifiers locating the instance, the `node_uuid`
locating the node inside its `DocumentNode` tree, and the new `value`.
```python
# app.py — update (excerpt)
db = CommitDatabase.open(FILENAME)
definitions = db.definitions()
concept = definitions.check_concept(concept_runtime_id)
key = ValueKey.create(concept, instance_id)
attachment_getting = db.state(db.last_commit_id()).attachment_getting()
doc = DocumentNode.create_documents(key, attachment_getting)
node = find_node(node_uuid, doc)
if node:
value = value_to_python(node, value)
state = db.state(db.last_commit_id())
mutable_state = CommitMutableState(state)
mutable_state.attachment_mutating().update(
node.attachment(), node.key(),
node.path().regularized().const(), value)
db.commit_mutations("Update From The Web", mutable_state)
return redirect(url_for("documents_node", ...))
```
This is the **canonical edit-commit pattern** that every dsviper
application repeats: open the current state, derive a
`CommitMutableState`, ask `attachment_mutating().update(...)` to apply
the change at a node path, then `commit_mutations(message, state)`.
The commit message — `"Update From The Web"` here — shows up in the
database's commit history exactly like any other client's mutation.
`value_to_python(node, value)` coerces the raw form string into the
Python type the node expects (`bool`, `int`, `float`, `str`); the
typed `update(...)` call enforces the rest at the dsviper layer.
After commit, the response is a `redirect` back to
`/documents_node/
///`. This rerenders the document
with the edited node's subtree left `open`, so the user keeps their
place in the tree — without a single line of JavaScript.
## Why "no JavaScript" is the point
Removing JavaScript is not a stylistic choice; it makes web-cdbe the
**minimum-surface demonstration** of the dsviper runtime in a web
context:
* No client-side framework, no build step, no transpiler — only Python,
Flask, Jinja, and the browser's native form handling.
* Every state transition is a normal HTTP request, so the server is the
single source of truth and the commit DAG is the only state machine.
* Anyone with a copy of dsviper can run the demo against their own
database and immediately see what's stored, what's editable, and what
changing it looks like in commit history.
## Where to read first
1. `app.py` lines around `abstractions` — the entry point and how the
schema is discovered.
2. `app.py` lines around `documents` — how a `DocumentNode` tree is
built from a `ValueKey`.
3. `html_documents_renderer.py` `render_value` — leaf nodes that
become editable HTML forms.
4. `app.py` lines around `update` — the open / mutate / commit
sequence every dsviper application repeats.
## Reference
* [dsviper](../dsviper/index.rst) — the runtime web-cdbe is built on,
including `CommitDatabase`, `CommitMutableState`, and `DocumentNode`.
* [DSM](../dsm/index.rst) — the modelling language whose definitions
are read back here through `db.definitions()`.