Files
qbit-scripting/docs/NATIVE-AUTHORING.md
f0d695ec97
QRun-IO/ci-policy: ci / fork-guard (push) Skipped
QRun-IO/ci-policy: ci / head-profile (push) Skipped
QRun-IO/ci-policy: ci / application-template-0 (push) Skipped
QRun-IO/ci-policy: ci / gradle-1 (push) Skipped
QRun-IO/ci-policy: ci / java-docker-3 (push) Skipped
QRun-IO/ci-policy: ci / java-docker-4 (push) Skipped
QRun-IO/ci-policy: ci / java-frontend-browser-5 (push) Skipped
QRun-IO/ci-policy: ci / java-maven-6 (push) Skipped
QRun-IO/ci-policy: ci / java-maven-7 (push) Skipped
QRun-IO/ci-policy: ci / node-8 (push) Skipped
QRun-IO/ci-policy: ci / node-9 (push) Skipped
QRun-IO/ci-policy: ci / node-10 (push) Skipped
QRun-IO/ci-policy: ci / node-playwright-11 (push) Skipped
QRun-IO/ci-policy: ci / repository-policy-12 (push) Skipped
QRun-IO/ci-policy: ci / source-config-13 (push) Skipped
QRun-IO/ci-policy: ci / source-config-14 (push) Skipped
QRun-IO/ci-policy: ci / android-0 (push) Skipped
QRun-IO/ci-policy: ci / original-business (push) Skipped
QRun-IO/ci-policy: ci / original-mcp (push) Skipped
QRun-IO/ci-policy: ci / original-voyage (push) Skipped
QRun-IO/ci-policy: ci / original-cli (push) Skipped
QRun-IO/ci-policy: ci / repository-policy (push) Skipped
QRun-IO/ci-policy: ci / java-core-2-head (push) Skipped
QRun-IO/ci-policy: ci / java-docker-3-head (push) Skipped
QRun-IO/ci-policy: ci / java-maven-6-head (push) Skipped
QRun-IO/ci-policy: ci / java-maven-7-head (push) Skipped
QRun-IO/ci-policy: ci / not-enrolled (push) Failing after 7s
QRun-IO/ci-policy: native / fork-deny (push) Skipped
QRun-IO/ci-policy: native / dotnet-0 (push) Skipped
QRun-IO/ci-policy: ci / ci-result (push) Failing after 6s
QRun-IO/ci-policy: native / native-result (push) Successful in 6s
chore: preserve paused QBit work and document remaining issues
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>
2026-11-04 10:45:28 -06:00

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.