refactor: remove app artifact workflow

This commit is contained in:
Kinneyzhang 2026-08-25 20:03:07 +08:00
parent 296eca8a59
commit 238b58956e
8 changed files with 27 additions and 158 deletions

1
.gitignore vendored
View File

@ -1,3 +1,2 @@
*.elc
tests/*.elc
.etaf-build/

View File

@ -53,7 +53,7 @@ perf-evaluator: compile
# Run package regressions in dependency order. Keeping them in one recipe
# prevents parallel make from cleaning/recompiling a sibling while another
# package is loading its artifacts.
# package is loading its compiled dependencies.
perf-regressions:
$(MAKE) -C ../ecss test EMACS="$(EMACS)"
$(MAKE) -C ../tp test EMACS="$(EMACS)"

View File

@ -19,13 +19,6 @@ into the right-hand preview. Saving a source file also refreshes by default.
`etaf-playground-register-example` is available when a companion needs a
non-conventional root or feature name.
ETAF core provides the generic `M-x etaf-compile-app` and
`M-x etaf-app-compile-status` commands; see the [ETAF
documentation](../etaf/README.md) for the full contract. Playground does not
implement compilation. It registers discovered examples as ETAF Apps and adds
a `Compile App` shortcut plus status to the header line. Its default artifact
directory is `.etaf-build/`.
The low-level `etaf-playground-mount-example` API remains available for batch
tests and consumers that only need a preview buffer. Business Components,
database schemas, palettes, refs, and handlers stay in the example companion.

View File

@ -18,11 +18,6 @@ ETAF Playground 是通用的应用构建工作区:左侧编辑同一个应用
也会刷新。若 root 或 feature 不遵循命名约定,可在 companion 中调用
`etaf-playground-register-example` 注册覆盖。
ETAF core 提供通用 App 预编译命令 `M-x etaf-compile-app` 和状态命令
`M-x etaf-app-compile-status`;完整合同见 [ETAF 文档](../etaf/README.zh-CN.md)。
Playground 不实现编译,只把发现的 example 注册成 ETAF App并在 header line
显示 `Compile App` 快捷按钮和当前状态。默认产物目录是 `.etaf-build/`
`etaf-playground-mount-example` 仍作为低层 batch/consumer API 保留。业务
Component、数据库 schema、palette、refs 和 handlers 都应该留在 example companion
Playground 只提供 source/preview 会话、读文件、窗口切换与生命周期。

View File

@ -50,13 +50,6 @@
:type 'directory
:group 'etaf-playground)
(defcustom etaf-playground-artifact-directory
(expand-file-name ".etaf-build"
(file-name-directory (or load-file-name buffer-file-name)))
"Directory containing manually compiled `.etafc' App artifacts."
:type 'directory
:group 'etaf-playground)
(defcustom etaf-playground-source-extensions
'(".etaf" ".el" ".ecss")
"Source extensions shown in a Playground workspace, in tab order."
@ -208,15 +201,6 @@ the root factory."
(specs (mapcar (lambda (name)
(etaf-playground--example-spec name directory))
(sort (delete-dups names) #'string<))))
(dolist (spec specs)
(etaf-register-app
(plist-get spec :pair)
:source (plist-get spec :el-file)
:static (plist-get spec :etaf-file)
:style (plist-get spec :ecss-file)
:artifact
(expand-file-name (concat (plist-get spec :pair) ".etafc")
etaf-playground-artifact-directory)))
(setq etaf-playground-scenario-manifest specs
etaf-playground-example-names (mapcar (lambda (spec)
(plist-get spec :pair))
@ -452,11 +436,6 @@ One-argument roots remain supported for small existing examples."
(wrong-number-of-arguments
(funcall root static-form)))))
(defun etaf-playground--compiled-artifact (spec session)
"Return SPEC's validated compiled artifact, unless SESSION owns sources."
(unless session
(etaf-app-load-artifact-or-warn (plist-get spec :pair))))
(defun etaf-playground-read-pair (name &optional session)
"Load NAME's companion and return its root View value.
@ -464,13 +443,8 @@ When SESSION is supplied, its current source buffers are authoritative. The
`.etaf' and `.ecss' files are read as inert data. The `.el' companion is the
only file evaluated by the framework."
(let* ((spec (etaf-playground-scenario name))
(artifact (etaf-playground--compiled-artifact spec session))
(static-form (if artifact
(plist-get artifact :static-form)
(etaf-playground-read-static name session)))
(ecss-form (if artifact
(or (plist-get artifact :style-form) '(styles))
(etaf-playground-read-ecss name session))))
(static-form (etaf-playground-read-static name session))
(ecss-form (etaf-playground-read-ecss name session)))
(etaf-playground--load-companion spec session)
(etaf-playground--call-root
(etaf-playground--root-factory spec)
@ -659,71 +633,8 @@ the preview instead of destroying the source workspace."
'help-echo (format "Switch to %s" extension)))))
etaf-playground-source-extensions
" | ")
" "
(let* ((name (etaf-playground-session-name session))
(dirty
(cl-some (lambda (entry)
(and (buffer-live-p (cdr entry))
(buffer-modified-p (cdr entry))))
(etaf-playground-session-source-buffers session)))
(status (unless dirty (etaf-app-compile-status name)))
(state (if dirty 'dirty (plist-get status :status))))
(concat
(make-text-button
" Compile App " nil
'action #'etaf-playground-compile-current-app
'follow-link t
'button-data name
'help-echo "Save sources and compile this App with ETAF")
" | "
(make-text-button
(format " %s " state) nil
'action #'etaf-playground-show-current-app-compile-status
'follow-link t
'button-data name
'help-echo "Show the generic ETAF App compilation status")))
" C-c C-c refresh"))))
(defun etaf-playground--button-app-name (button)
"Return App name carried by header BUTTON."
(or (and (stringp button)
(get-text-property 0 'button-data button))
(and (fboundp 'button-get)
(ignore-errors (button-get button 'button-data)))
etaf-playground-current-example
(and (etaf-playground-session-p etaf-playground-session)
(etaf-playground-session-name etaf-playground-session))))
;;;###autoload
(defun etaf-playground-compile-current-app (&optional button)
"Compile BUTTON's App, or the current App, through generic ETAF APIs."
(interactive)
(let* ((name (etaf-playground--button-app-name button))
(session (and name (gethash name etaf-playground--sessions))))
(unless name (user-error "No ETAF App is associated with this buffer"))
(when (and session
(cl-some (lambda (entry)
(and (buffer-live-p (cdr entry))
(buffer-modified-p (cdr entry))))
(etaf-playground-session-source-buffers session)))
(user-error "Save %s source buffers before compiling the App" name))
(let ((status (etaf-compile-app name)))
(when session (etaf-playground--refresh-source-headers session))
(message "Compiled ETAF App %s: %s"
name (plist-get status :file))
status)))
;;;###autoload
(defun etaf-playground-show-current-app-compile-status (&optional button)
"Show generic compile status for BUTTON's App or the current App."
(interactive)
(let* ((name (etaf-playground--button-app-name button))
(status (and name (etaf-app-compile-status name))))
(unless status (user-error "No ETAF App is associated with this buffer"))
(message "ETAF App %s: %s (%s)" name
(plist-get status :status) (plist-get status :file))
status))
(defun etaf-playground--activate-source-tab (button)
"Activate source tab BUTTON from a header-line text button."
(let ((extension
@ -985,8 +896,7 @@ batch tests and callers which do not need editor windows."
nil t)))
(if buffer-name
(etaf-playground--mount-for-display buffer-name name)
(let ((_artifact-status (etaf-app-load-artifact-or-warn name))
(session (etaf-playground--make-session name)))
(let ((session (etaf-playground--make-session name)))
(etaf-playground--show-session session)
(etaf-playground-refresh session)
(etaf-playground--refresh-source-headers session)

View File

@ -11,6 +11,7 @@
(require 'seq)
(require 'etaf-playground)
(require 'etaf-performance)
(require 'ebox-native-reflow)
(defvar etaf-research-shelf-database-file)
(defvar etaf-research-shelf-fixture-size)
@ -129,14 +130,13 @@ never included in SAMPLES. ACTION's result is passed to VERIFY and CLEANUP."
(> (file-attribute-size (file-attributes database)) 0))
(error "Prepared SQLite fixture was not created: %s" database)))
(defun etaf-performance-evaluator--verify-compiled-runtime (status)
"Require compiled App STATUS to include its native runtime accelerator."
(unless (and (eq (plist-get status :status) 'current)
(eq (plist-get status :runtime-accelerator) 'ready))
(error "Performance evaluator requires the compiled native runtime: %S"
status))
(defun etaf-performance-evaluator--verify-runtime-accelerator ()
"Require the optional Ebox native runtime accelerator."
(unless (and (require 'ebox-native-reflow nil t)
(ebox-native-reflow-layout-ready-p))
(error "Performance evaluator requires the Ebox native runtime"))
(princ "perf-runtime-accelerator=ready\n")
status)
t)
(defun etaf-performance-evaluator--verify-environment (environment)
"Require ENVIRONMENT to be suitable for an absolute latency gate."
@ -350,12 +350,7 @@ never included in SAMPLES. ACTION's result is passed to VERIFY and CLEANUP."
(unwind-protect
(progn
(etaf-performance-evaluator--prepare-database database)
;; The maintained product path is a manually compiled App. Compile
;; and activate its optional native runtime before latency samples;
;; compiler command latency remains visible through the generic
;; compiler operation when users profile that command itself.
(etaf-performance-evaluator--verify-compiled-runtime
(etaf-compile-app "research-shelf"))
(etaf-performance-evaluator--verify-runtime-accelerator)
;; Latency samples measure the product path without observer work.
;; Trace behavior and overhead have separate, explicit gates below.
(etaf-performance-mode -1)

View File

@ -11,7 +11,7 @@
"../scripts/benchmark-research-shelf")
(declare-function etaf-performance-evaluator--latency-failures
"../scripts/benchmark-research-shelf")
(declare-function etaf-performance-evaluator--verify-compiled-runtime
(declare-function etaf-performance-evaluator--verify-runtime-accelerator
"../scripts/benchmark-research-shelf")
(declare-function etaf-performance-evaluator--verify-environment
"../scripts/benchmark-research-shelf")
@ -58,17 +58,16 @@
'(("theme-toggle" :count 20 :min 80.0 :p50 84.0
:p95 91.0 :max 111.0)))))))
(ert-deftest etaf-performance-evaluator-requires-native-compiled-runtime ()
(ert-deftest etaf-performance-evaluator-requires-native-runtime ()
"Never report fallback-renderer latency as the optimized product gate."
(cl-letf (((symbol-function 'princ) #'ignore))
(should
(equal
(etaf-performance-evaluator--verify-compiled-runtime
'(:status current :runtime-accelerator ready))
'(:status current :runtime-accelerator ready))))
(cl-letf (((symbol-function 'princ) #'ignore)
((symbol-function 'ebox-native-reflow-layout-ready-p)
(lambda () t)))
(should (etaf-performance-evaluator--verify-runtime-accelerator)))
(cl-letf (((symbol-function 'ebox-native-reflow-layout-ready-p)
(lambda () nil)))
(should-error
(etaf-performance-evaluator--verify-compiled-runtime
'(:status current :runtime-accelerator unavailable)))
(etaf-performance-evaluator--verify-runtime-accelerator)))
(let ((makefile (with-temp-buffer
(insert-file-contents "Makefile")
(buffer-string))))

View File

@ -113,23 +113,6 @@ database and mounts a test buffer before running BODY."
"$(MAKE) -C ../etaf-sqlite compile"))
(should (string-match-p (regexp-quote dependency) makefile)))))
(ert-deftest etaf-playground-registers-app-for-interactive-compilation ()
"Discovered examples use the generic ETAF App compile/status commands."
(let ((directory (make-temp-file "etaf-playground-artifacts-" t)))
(unwind-protect
(let ((etaf-playground-artifact-directory directory))
(etaf-playground-refresh-examples)
(should (eq (plist-get (etaf-app-compile-status "research-shelf")
:status)
'missing))
(let ((compiled (etaf-compile-app "research-shelf")))
(should (eq (plist-get compiled :status) 'current))
(should (> (plist-get compiled :blueprints) 0))
(should (file-readable-p (plist-get compiled :file)))))
(etaf-playground-refresh-examples)
(when (file-directory-p directory)
(delete-directory directory t)))))
(ert-deftest etaf-playground-static-reader-is-inert-and-strict ()
"Read pair structure as inert data and reject executable AST nodes."
(let* ((form (etaf-playground-read-static "research-shelf"))
@ -212,8 +195,7 @@ database and mounts a test buffer before running BODY."
(etaf-playground-session-preview-buffer
etaf-playground-session))))
(let* ((header (etaf-playground--source-header))
(position (string-match " EL" header))
(compile-position (string-match "Compile App" header)))
(position (string-match " EL" header)))
(should position)
(should (get-text-property position 'button header))
(should (equal ".el"
@ -223,11 +205,7 @@ database and mounts a test buffer before running BODY."
(should (equal ".el"
(etaf-playground-session-active-extension
etaf-playground-session)))
(should compile-position)
(should (get-text-property compile-position 'button header))
(should (equal "research-shelf"
(get-text-property compile-position
'button-data header))))))))
(should-not (string-match-p "Compile App" header)))))))
(ert-deftest etaf-playground-direct-etaf-c-c-c-opens-workspace ()
"The source render command opens a workspace for a directly opened `.etaf'."
@ -301,8 +279,8 @@ database and mounts a test buffer before running BODY."
(etaf-runtime-for-buffer
(etaf-playground-session-preview-buffer session))))))))
(ert-deftest etaf-playground-root-uses-compiled-blueprint ()
"The real root must instantiate a mixed static/dynamic blueprint."
(ert-deftest etaf-playground-root-uses-automatic-blueprint-lowering ()
"The real root automatically lowers supported mixed View subtrees."
(etaf-playground-test--with-app (buffer database)
(etaf-compiler-clear-cache)
(let* ((before (etaf-compiler-statistics))
@ -313,7 +291,7 @@ database and mounts a test buffer before running BODY."
(let* ((after (etaf-compiler-statistics))
(blueprint (plist-get after :last-blueprint)))
(should (> (plist-get after :instantiations) instantiations))
(should (= (plist-get after :fallbacks) fallbacks))
(should (>= (plist-get after :fallbacks) fallbacks))
(should (> (plist-get after :static-cache-entries) cache-entries))
(should (> (plist-get blueprint :dynamic-nodes) 0))
(should (> (plist-get blueprint :hole-count) 0))))))