Repository navigation
Build the Scantle control plane, isolated candidate verifier, contract diff engine, and orders reference platform - #1
Merged
Merged
Conversation
The orders example kept every run, checkpoint and run record in goa-ai's in-memory store, so restarting the orders process lost suspended refund approvals and run history. The new runstore package implements storage.Store and the host session methods on one SQLite file (modernc.org/sqlite, WAL, busy timeout). Each Store method runs in one SQLite transaction. Mutations begin with BEGIN IMMEDIATE, so the write lock is held from the first invariant check to commit, and several Store handles on one file serialize correctly. The checks and writes port goa-ai's inmem store method by method; unique keys and conditional updates enforce the single-winner rules inside the transaction: one record per (run, event key) and position, one seed record per (attempt, key) and position, one published attempt per run (partial unique index), and one successor per suspension (conditional UPDATE on the unresolved resolution). The contract suite ports 71 of inmem's 75 tests to the public Store API and runs each case against both inmem.New() and the SQLite store. The four tests not ported corrupt inmem's private maps. SQLite-only tests cover close/reopen durability and two handles racing a seed publication and a continuation. cmd/orders opens the store at --state-dir (default .scantle/state, file orders-runtime.db) and closes it after the engine stops. The orders-eval e2e test passes a temporary --state-dir.
A review against goa-ai's inmem store found inputs where the SQLite store returned different values: - Rendered prompt text with invalid UTF-8 was rewritten by JSON, so an exact BeginRunSeed retry conflicted. Prompts are now gob-encoded. - Times were Unix nanoseconds, which cannot represent dates outside 1678-2262 and dropped a record timestamp's zone offset. Time columns now hold time.Time's binary encoding. - FindRunPreparation and SettleRunPreparation could return found=true with a database error; they now return found=false on any error. - A rejection joined with a rollback failure kept only the database error; the joined error is now returned unwrapped. A new contract case runs these inputs against both stores.
# Conflicts: # examples/orders-eval/e2e/e2e_test.go
confirm_intent rejected every card whose status was not needs_confirmation, so a request that propose_change confirmed on its own could never have its examples edited, and a confirmed card could not take a corrected answer without a new change_id. confirm_intent now accepts needs_confirmation or confirmed cards. The owner sends the complete answers and examples against the card's current request_revision; a stale revision is refused. Changed answers or examples confirm the card under a new revision, so previews bound to the old one are refused; unchanged ones produce the same revision and return the card as it is. The prompt, summary and preserved behaviors are never changed here. The diff tool now links ui://scantle/checkpoint, so an MCP Apps host can render diff results.
Now that confirm_intent can refine a confirmed card, two editors can
work on one card. The one that saves second is refused with a stale
request_revision, and nothing could read the card the other saved: an
app-initiated save need not appear in the chat, and propose_change
refuses an existing change_id.
get_change(change_id) returns the stored ChangeCardResult to its owner
(GET /changes/{change_id}, and an MCP tool linked to the checkpoint
viewer). It reads the existing card, never changes it, and fails for an
unknown change_id or another principal. A test runs the two-editor case:
B saves, A is refused, A reads B's card and resubmits against it.
controlplane.go had grown past 1,000 lines. The four Checkpoint 1 validators (validateCP1Analysis, validateAmbiguities, validateAmbiguityAnswers, validateConfirmedExamples) move unchanged into their own file; no behavior changes.
…ult viewer to CheckpointUI
…tra-column C4 SVG routing
…document Phase 9 tools
…e error status, and label example inputs
…rols in flight, and retain editor on pending notifications
The CP1 model can now return an optional ui_composition: an OpenUI Lang
program built from the decision component catalog that helps the
operator decide the open questions. ProposeChange returns it on the
Change Card as UICompositionItem{program, composed_for_revision}, bound
to the revision it was composed with but never hashed into it, so
request_revision, confirm_intent and verify stay independent of it.
The program refers to ambiguities and examples by their 1-based position
in the analysis, because the model never sees the change_id and the
server assigns <change>-ambiguity-NN and <change>-check-NN from that same
order after the response. A blank program is rejected.
A confirm_intent that changes answers or examples returns the new
revision without the composition, and get_change never restores it; an
unchanged submission returns the stored card, composition included.
ProposeChange and PreviewArchitecture report MCP progress around the
model call, the design evaluation and the swarm plan. The CP1 output
allowance rises from 4096 to 6144 tokens for the composition. The
catalog prompt is embedded from internal/goldenpath/decision_catalog.md,
which the checkpoint UI build writes; this commit adds a placeholder.
The SSE test now proposes a change whose analysis carries a composition and asserts the whole stream: both progress notifications first, then exactly one result answering request 1, carrying the card with its ui_composition program byte for byte and composed_for_revision equal to request_revision.
ProposeChange rejected a whitespace-only ui_composition, and the CP1 schema's minLength made the model client reject an empty one, so a composition the viewer could not use cost the operator the whole analysis: no questions, no examples, no card. The composition is presentation only. The schema now accepts any string, UICompositionItem.program has no length rule, and ProposeChange carries whatever the model returned, byte for byte, bound to its revision. The checkpoint viewer already validates programs and keeps the rest of the card usable when one is invalid. Tests cover an absent, empty, whitespace-only, unparsable and catalog program.
…space-level qualification
…tion in OpenUI studio
…Zod schema validation
…sh primary copy with Details disclosures
…osed on unknown schema keywords, and use plain-English status copy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A user submits a change through
propose_change, and Scantle returns a Change Card with a summary, unresolved questions, concrete examples, and preserved behaviors. This PR adds the Goa-designed HTTP/MCP control plane and checkpoint viewer for reviewing that card.confirm_intentsaves the owner's complete answers and example table against the currentrequest_revision; stale submissions fail. The original prompt, summary, and preserved behaviors remain intact. Changed answers or examples produce a new revision and discard the earlier UI composition; repeating an unchanged confirmation returns the stored confirmed card.get_changelets the owner recover the current card after a stale-editor error.preview_architectureevaluates a submitted design for the confirmed revision in a sandbox and returns the C4 graph, agent policies, tool contracts, and a proposed swarm roster.diffcompares design andgo.modstructure independently of a card.draft_overrideupdates a prompt template when an embedding host providesOptions.TargetUpdater; standaloneserverejects that update, and compiled-rule changes returnrequires_rebuild: true. These six tools share theui://scantle/checkpointMCP App resource. The server also exposes the Golden Path Markdown resource.The checkpoint viewer renders model-authored OpenUI policy comparison tables, ambiguity choices, workflow timelines, and impact callouts alongside the full intent form. Both views edit the same
CP1DraftContext: selecting an option in a comparison table changes the answer shown in the form and submitted toconfirm_intent. A missing, stale, or invalid composition leaves the form usable. The viewer preserves unsaved edits across unrelated results and provides explicit recovery when a saved revision has changed. Model-proposed outcomes and local example edits are labeled accordingly. Architecture graphs, structural diffs, and technical details remain available on demand in light and dark layouts.The OpenUI component definitions also generate the catalog embedded in the model prompt. The UI build derives its TypeScript wire types and runtime result checks from the Goa-generated tool result schemas, and fails when an unsupported schema constraint appears. Partial tool arguments can update the request preview.
propose_changeandpreview_architecturesend MCP progress updates as analysis, design evaluation, and roster planning start and finish, when the caller's request includes aprogressTokenand the host relays them.Scantle also includes isolated design/candidate evaluation and verification packages, with verification exposed separately through the
scantle verifyoperator CLI. Architecture preview returns a proposed team roster; the public control-plane flow does not launch builders or approve merges. The implementation pins prerelease Goa, Goa-AI, and Model commits ingo.mod.Published
@openuidev/lang-core@1.0.2can still silently ignore bare expressions, empty assignments, and trailing tokens. Integration proceeds with that known limitation. OpenUI #1525 adds parser-ownedinvalid-statementandtrailing-tokensdiagnostics inParseResult.meta.discarded. After a fixed upstream release is selected in Scantle's lockfile, the existing check invalidateCompletedOpenUIrejects programs with those diagnostics without viewer code changes. The 24-case validator pass used a local build of that parser patch; it does not establish that the published dependency reports discarded source.Native Safari verification exercised the actual served viewer at 390px in light and dark modes, including shared drafts, stale-revision recovery, and preservation of saved example text. This used a controlled parent relay; compatibility with a named production MCP Apps host remains unverified.