Save the current implementation and README, status, and known-issue documentation at the user-requested stop. No completed release or deployment is claimed. Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: GPT-6 Codex <noreply@openai.com>
6.3 KiB
Native scripting authoring
The producer installs standard QQQ processes on the Script table. A client needs ordinary process discovery/execution, EDIT_FORM, VIEW_FORM, possible-value choices and optional CODE_EDITOR adornments. The enhanced source widget is an additional editing experience; these forms do not depend on Next, a browser-specific route or a separate service.
| Process | Native flow | Semantic owner action |
|---|---|---|
scripting_create_project |
Name → isolated project link | createProject |
scripting_add_file |
Selected project → relative .ts path/source/note → saved revision |
Optimistic saveDraft |
scripting_edit_file |
Selected project → current file choice → exact source editor/note → saved revision | Project-scoped draft, optimistic saveDraft |
scripting_rename_file |
Selected project → current file choice → readonly old path, new path/note → saved revision | Project-scoped draft, optimistic saveDraft |
scripting_remove_file |
Selected project → current file choice → readonly path/note → saved revision | Project-scoped draft, optimistic saveDraft |
scripting_import_commit |
Selected project → repository/exact commit/optional directory → retained provenance and draft revision | Existing configured importer, optimistic importDraft |
scripting_check_draft |
Selected project → pinned latest revision, entrypoint choice, declarations JSON → diagnostics/build link | check |
scripting_test_context |
Selected project → pinned latest successful build, context JSON, grants JSON → result/execution link | testContext |
scripting_publish_build |
Selected project → authorized successful-build choice/note → publication link | publish |
Add/edit reconstruct the immutable base file list and change exactly one file; other files remain byte-for-byte unchanged. Source changed after form preparation is refused, including stale check forms. Existing service limits remain: at most200 files,256KiB per source file and2MiB total. Native code fields are presentation; server path/byte/snapshot validators remain authoritative.
Rename/remove use the same complete immutable snapshot and expected-revision check. The selected path is loaded by the backend and readonly on the final form. Rename preserves that file's contents and rejects unsafe paths, unchanged names and case-insensitive collisions with other files; a case-only rename of the selected file is valid. Remove omits only that file from the new draft and refuses removal of the last file. Neither operation modifies earlier revisions, builds, publications or bindings, and neither builds or publishes automatically. Imports and configured entrypoints are not rewritten: review the new draft and run Check before testing/publishing. These are file operations, not TypeScript symbol refactoring.
ScriptingFileActionsProcessTest covers metadata/selection, immutable history, unchanged imports, path/collision/case rules, stale selection/submit, current permission and credential refusal, and nonempty projects. Execution results belong to the matching verification log; host fixtures do not execute source code.
Read-only form fields and possible-value choices do not grant authority. Every backend step rechecks current user/project/action access; submitted revisions/builds must belong to that authorized isolated project. Publication uses the exact selected build and the existing requirement for a passing test of that build. A later draft does not change the tested artifact. Build choices are the bounded recent100 owner history; the semantic API remains available for advanced/history workflows.
Capabilities are an explicit JSON array, for example:
[{"operation":"READ","table":"purchase_order","fields":["id","status"],"maxRows":10,"maxCalls":2}]
Default [] grants nothing. Unknown properties, non-READ operations, coerced number strings and invalid budgets fail closed. Native forms reuse the existing bounded JSON codec and capability constructors; actual test grants must be within the signed build declaration and the current caller's read authority. Context input is a bounded JSON object. No capabilities, source or record context are inferred from browser state.
Checking/testing/publishing still requires the configured, qualified external worker and current named permissions. Forms do not enable a fallback runtime. Host tests use a protocol fixture, not JavaScript execution; native HTTP/real-worker acceptance is separately owned and must be recorded after its gate.
Project visibility with host record security
Script projects are the core script table. Project access is the caller's own enforced QQQ Get of that row, so
native record-security locks configured by the host apply exactly as for any QQQ table: a host that locks the table
(for example by tenant) gets projects private to their lock value. The owner can create, view, check, test, publish
and bind; another tenant holding the same lifecycle permissions is refused for the project, its revisions, builds,
publications and bindings, and ordinary table reads of the child tables return nothing. Lifecycle permissions
(scripting.draft/check/test/publish/bind/execute) stay separate from visibility. Without a lock, projects are
shared by anyone holding the permission (the unchanged default).
The QBit itself reads and writes its project tables as the QQQ system session after authorization. QQQ lets that
session through a lock only when the lock's QSecurityKeyType defines an all-access key
(withAllAccessKeyName). Producing the QBit therefore refuses a locked script, scriptRevision or
scriptRevisionFile table whose key type defines none, with the table and key type named. (Before this check such a
configuration started, then failed every authoring call for the owner as "not found".) Locks are never bypassed
and no key value is inferred from the actor; configure the key type and stamp the lock field on project creation
with an ordinary table customizer.
Execution of an already-bound hook is not tied to the end user's project visibility: a binding pins its immutable publication at bind time, and later saves by users outside the project's lock value still run the bound hook. The binding's tenant scope is whatever the host declares for the hooked table; Scripting adds no separate namespace.