programmati.ca Open Studio
Return to Research
HOWTO

Keep generated UI inside a tested AppSPEC template

A runnable create/edit/delete example and a small JSON contract that keeps layout, navigation and behavior under code control.

Try the working example Edit in Studio

Practical workflow

Run the fixed example

Open the starter and add a note. Open its row, change the text and save. Reload the page: the edited record should still be present. Delete it and reload again: it should remain absent.

Give the model a bounded contract

Ask for title_label and note_label as plain text, each at most 40 characters. Reject extra keys, empty values, URLs, markup and scripts. Keep the XML below as the template; insert the two validated labels with an XML library that escapes attribute values.

Keep the state graph in code

The template owns DATA, FORM, TABLE, state IDs, storage collection and DELETE wire. Let the model name fields, rather than inventing navigation, wrappers or event handlers. Freeze the template while repairing the model contract.

Test the task rather than the screenshot alone

Create a record, edit its text, reload, delete it, and reload again. Check a 390-pixel viewport for overflow. Check browser console errors and failed requests. Check the canonical shell boundaries separately from the app content.

Evaluate the remaining design work

A stable template reduces structural variation. It does not choose the right product task, establish visual quality or prove that people need the result. Review the empty state, wording, hierarchy and task fit before release.

The bounded model response

{"title_label":"Note title","note_label":"Note text"}

Apply the labels with Python

import re
import xml.etree.ElementTree as ET

def apply_labels(contract, template):
    if set(contract) != {"title_label", "note_label"}:
        raise ValueError("Unexpected contract keys")
    for text in contract.values():
        if (not isinstance(text, str) or not text.strip() or len(text) > 40
                or re.search(r"[<>\x00-\x1f]|https?://|javascript:", text, re.I)):
            raise ValueError("Invalid label")
    root = ET.fromstring(template)
    for field in root.iter("FIELD"):
        key = "title_label" if field.get("NAME") == "title" else "note_label"
        field.set("LABEL", contract[key])
    ET.indent(root, space="  ")
    return ET.tostring(root, encoding="unicode")

# template is the fixed XML shown below, held by your code.
# new_spec = apply_labels({"title_label": "Task", "note_label": "Details"}, template)
# Open new_spec in Studio and repeat the workflow checks.

The fixed AppSPEC template

<?xml version="1.0" encoding="UTF-8"?>
<APP ID="constrained-ui-starter" NAME="Constrained UI Starter" THEME="modern-minimal" WIDTH="1240px">
  <DATA MODE="local" />
  <STATE ID="notes" NAV="Notes" ICON="list">
    <TEXT STYLE="h1" TEXT="Build a task list from data" />
    <TEXT STYLE="muted" TEXT="Create, edit and delete local notes using a fixed layout. Change labels while keeping the AppSPEC structure stable." />
    <TEXT STYLE="muted" TEXT="Try it: add a note, open its row, edit it, then reload. Delete the note and reload again. Changes stay in this browser." />
    <FORM SAVE="recipe_notes" SUBMIT-LABEL="Add note" COLS="2">
      <FIELD NAME="title" LABEL="Note title" PLACEHOLDER="For example: Check mobile navigation" REQUIRED="true" />
      <FIELD NAME="body" LABEL="Note text" PLACEHOLDER="For example: Verify Docs opens with the keyboard" REQUIRED="true" />
    </FORM>
    <TABLE SRC="recipe_notes" OPEN="edit" EMPTY="No notes yet. Add one above to try the workflow.">
      <COL FIELD="title" LABEL="Title" />
      <COL FIELD="body" LABEL="Note" />
    </TABLE>
  </STATE>
  <STATE ID="edit" WIDTH="640px">
    <TEXT STYLE="h1" TEXT="Edit note" />
    <FORM UPDATE="recipe_notes" TO="notes" SUBMIT-LABEL="Save changes">
      <FIELD NAME="title" LABEL="Note title" REQUIRED="true" />
      <FIELD NAME="body" LABEL="Note text" TYPE="textarea" REQUIRED="true" />
    </FORM>
    <BUTTON LABEL="Delete note" ACTION="remove" STYLE="danger" ICON="trash-2" />
  </STATE>
  <WIRE LABEL="remove" DELETE="recipe_notes" TO="notes" />
</APP>

Source and scope

A public developer question prompted this walkthrough. It demonstrates a constrained template approach; it does not measure how often the reported problem occurs.

This is an educational starter with local browser storage. It has no account sync, server writes or automatic design evaluation. Labels alone cannot express every application.

This example passed real browser create, edit, reload, delete and mobile checks. These checks do not establish customer value.