DEV Community

canonical
canonical

Posted on

NOP Chaos Flux Architecture Evolution: Rewriting from AMIS to a Modern Low-Code Runtime

This article is based on the development logs under docs/logs/2026/ (2026-03-20 to 2026-05-03), sorting out the architectural decisions, module splits, performance optimizations, and platform evolution of the entire framework from zero to maturity. Each phase includes key code paths and document links for traceability.

This article is a collation of historical evolution and implementation trajectory, not a current normative owner doc. For judgments involving current primitive boundaries, action execution model, resource publishing contracts, template instantiation, or package boundaries, the current owner docs and live code pointed to by docs/architecture/README.md shall prevail.

The "key path" filenames appearing in the text are recorded according to the repository state at that time; some paths may have been moved, split, or deleted today and should not be used as current entry indexes.


Preface: Source of Design Ideas

The core design ideas of Flux were not discovered gradually during implementation, but were established as early as the AMIS theory research phase. The two articles under nop-entropy/docs/theory/amis/Why Baidu AMIS Framework is an Excellent Design and Revisiting Baidu AMIS Framework and Declarative Programming — laid the theoretical foundation for the entire project:

  • Env environment abstraction: AMIS's env object virtualizes all I/O operations, making output = AmisPage(Input) possible. Flux's RendererEnv is a modern implementation of this idea.
  • Api and value/function duality: The Api object is a Ref encapsulation of remote async calls, essentially an asynchronous upgrade of computed. Flux's Resource (data-source) primitive directly inherits this idea.
  • Data chain = lexical scope: AMIS's data chain is essentially lexical scope lookup at the DSL level. Flux's ScopeRef chain structure is a compile-time enhancement of this model.
  • xui:import action modularization: The xui:import attribute introduced by the Nop platform for AMIS injects external function libraries into the action system by lexical scope. Flux's xui:imports + ActionScope is a complete compile-time implementation of this mechanism.
  • Declarative first: From imperative DOM manipulation to reactive data binding to compiled artifact execution — each step increases the proportion of declarativeness. Flux's compile-first principle is the endpoint of this evolution.

Therefore, the architectural evolution of Flux is not "discovering principles during design" but "systematically implementing established principles on a modern technology stack (React 19, Zustand, TypeScript 6.0)". The evolution history records split decisions, performance breakthrough bottlenecks, and contract refinements on the implementation path, not swings in design direction.

The Most Fundamental Shift: From Runtime Interpretation to Compile-Time Execution

The above principles answer "what to design"; the most fundamental implementation shift throughout the evolution is "how to execute":

AMIS is essentially a runtime interpreter — takes a JSON schema, reads and executes it on the fly. Data chain is looked up at runtime, actions are dispatched at runtime, validation is triggered at runtime, field visibility is judged at runtime. All design principles operate at the runtime level.

Flux inserts a compilation phase between DSL and runtime, moving forward various categories of AMIS runtime behavior into compiled artifacts:

AMIS Runtime Behavior Flux Compiled Artifact
Runtime type judgment of values CompiledValueNode five static node types
Runtime traversal of schema structure TemplateNode immutable graph (compile once, instantiate multiple times)
Runtime resolution of actions CompiledActionProgram / CompiledActionNode IR
Runtime wiring of host contracts CapabilityProjectionManifest compile-time visible and verifiable
Runtime exposure of schema problems Compile-time diagnostics (unknown attributes, contract shape validation)

This shift was not completed at once but runs through the entire evolution process as the main thread: from value compilation (03-25) to template instantiation (04-07) to action pre-compilation (04-20) to compiler package extraction (04-21) — each step is a milestone on the same path of "moving runtime judgment forward to compile time". The final three-layer split of flux-compiler / flux-action-core / flux-runtime is the physical form of this shift: the compiler is responsible for producing immutable artifacts, and the runtime only consumes and instantiates them.


Table of Contents

  1. Phase 1: Core Concept Establishment and Package Structure Setup
  2. Phase 2: Flow Designer from Proof of Concept to Production-Grade
  3. Phase 3: Renaming, Styling System, and Component Migration
  4. Phase 4: Complex Renderers and Architecture Audit
  5. Phase 5: Code Audit and Quality Convergence
  6. Phase 6: Runtime Architecture Convergence and Performance Optimization
  7. Phase 7: Frontend Programming Model Finalization and In-depth Design
  8. Phase 8: Template Instantiation and Node Identity System
  9. Phase 9: Deep Audit, Performance Optimization, and Architecture Convergence
  10. Phase 10: Compiler Independence and Package Boundary Hardening
  11. Phase 11: Comprehensive Quality Convergence and Host Maturity
  12. Key Principles of Architectural Evolution
  13. Appendix: Timeline Overview

1. Phase 1: Core Concept Establishment and Package Structure Setup

Time: 2026-03-20 ~ 2026-03-23

On 03-20, systematic bug analysis and first-round fixes of the early Flux runtime were completed (dual-state desynchronization, concurrent submit race, validation coverage, etc.). On the same day, @nop-chaos/amis-debugger (later renamed nop-debugger) was created, positioned from the start as an AI-first structured diagnostic tool.

1.1 Action Scope and Import Semantics

docs/architecture/action-scope-and-imports.md established one of the most core conceptual layers of Flux:

  • ScopeRef is a pure data scope, only carrying data reads/writes.
  • ActionScope is a capability scope, carrying namespaced actions and imported library capabilities.
  • xui:import is declarative import semantics (order-independent, repeatable, deduplicated by normalized key), not execution order semantics.

The dispatch path is fixed as: built-in → component:<method> → namespaced action.

1.2 Flow Designer Package Creation

The two packages @nop-chaos/flow-designer-core and @nop-chaos/flow-designer-renderers were created in this phase. Core contains the pure graph runtime (GraphDocument, GraphNode, GraphEdge, DesignerConfig), and Renderers contains renderer definitions for designer-page, designer-field, designer-canvas, designer-palette.

1.3 Collaborative Documentation System

The complexity of Flow Designer gave birth to a layered documentation system:

  • docs/architecture/flow-designer/design.md — target architecture
  • docs/architecture/flow-designer/runtime-snapshot.md — current implementation snapshot
  • docs/architecture/flow-designer/collaboration.md — runtime collaboration boundaries
  • docs/architecture/flow-designer/canvas-adapters.md — canvas adapter boundaries

Key decision: Split documentation into "target state" and "snapshot state" to avoid confusion between target architecture and current implementation.

Key paths: packages/flux-runtime/src/action-runtime.ts, packages/flow-designer-core/src/core.ts, docs/architecture/action-scope-and-imports.md


2. Phase 2: Flow Designer from Proof of Concept to Production-Grade

Time: 2026-03-23 ~ 2026-03-27

2.1 Canvas Bridge Pattern

Introduced the DesignerCardCanvasBridge contract, abstracting canvas interactions (select, delete, move, connect, reconnect, viewport sync) as bridge callbacks, allowing the card canvas and XYFlow canvas to share the same command adapter.

Renderer UI Events → Bridge Callbacks → Command Adapter → Core Mutations
Enter fullscreen mode Exit fullscreen mode

Key decision: Replacing the canvas renderer does not require reintroducing direct graph mutation paths. All mutations go through the shared command adapter.

2.2 Command Adapter

designer-command-adapter.ts introduced a target-side command normalization layer, providing a unified result shape of ok/snapshot/data/error/reason. Both Provider and canvas bridge dispatch commands through this surface, avoiding fragmented semantic rejection logic.

2.3 Schema-Driven Designer

Flow Designer completed the migration from hardcoded React components to JSON configuration-driven. Node/edge rendering is defined through the body: SchemaInput field, allowing complex node appearances to be composed using AMIS schemas such as flex, container, tpl, icon. classAliases and themeStyles enable theme customizability.

2.4 Production-Grade Visual Alignment

Completed visual alignment with the flow-editor-static.html prototype, unifying node two-line semantics, selection states, palette icon chips, quick action buttons, edge/label tokens, minimap anchor positions, etc.

Key paths: packages/flow-designer-renderers/src/canvas-bridge.tsx, packages/flow-designer-renderers/src/designer-command-adapter.ts, apps/playground/src/schemas/workflow-designer-schema.json


3. Phase 3: Renaming, Styling System, and Component Migration

Time: 2026-03-25 ~ 2026-03-29

3.1 AMIS → Flux Renaming

Comprehensively migrated package references and documentation from the AMIS namespace to the Flux namespace:

  • amis-schemaflux-core
  • amis-runtimeflux-runtime
  • amis-reactflux-react
  • amis-debuggernop-debugger
  • Window global variables renamed from __NOP_AMIS_* to __NOP_FLUX_*

3.2 flux-core Modular Split

packages/flux-core/src/index.ts (1183 lines) was split into a modular structure:

  • types.ts (687 lines) — all type definitions
  • validation-model.ts (174 lines) — validation model functions
  • utils/object.ts — object utilities
  • utils/path.ts — path utilities
  • utils/schema.ts — schema utilities
  • constants.ts — constants

3.3 Styling System Established

docs/architecture/styling-system.md established a TailwindCSS-first styling solution:

  • Semantic attributes (direction, gap, align) as syntactic sugar for Tailwind classes
  • classAliases mechanism for reusable Tailwind class definitions, supporting nested alias expansion and scope inheritance
  • Layout renderers only emit marker classes (nop-container, nop-flex), marker classes carry no visual styling
  • Spacing explicitly declared in schema via stack-*/hstack-* aliases

3.4 shadcn/ui Migration

Created @nop-chaos/ui package, based on the shadcn/ui component library pattern (class-variance-authority + tailwind-merge + lucide-react), migrating the underlying layer from radix-ui to base-ui:

  • Button, Input as first migrated components
  • Gradually covering the full component set: Textarea, Checkbox, Switch, RadioGroup, Select, Dialog, Tabs, Table, Card, etc.
  • First batch of renderers (Button, Input, Form) migrated to @nop-chaos/ui, subsequent renderers follow in batches

3.5 RendererComponentProps Contract

Established the RendererComponentProps pattern that all renderers must follow:

Data Source Provides Purpose
props.props Compiled runtime values Schema-driven values
props.meta Compiled metadata Control state
props.regions Pre-compiled child render handles Render child fragments
props.events Runtime event handlers Event binding
props.helpers Stable runtime helpers dispatch, evaluate

3.6 FieldFrame and Renderer Wrapping Contract

The FieldFrame component was introduced into the flux-react layer to uniformly handle form label/error/hint wrapping. The RendererDefinition.wrap flag lets NodeRenderer automatically add labels and error displays for renderers that need field wrapping.

3.7 Report Designer and Spreadsheet Migration

Migrated four packages from nop-chaos-next into the workspace (completed 03-25):

  • @nop-chaos/spreadsheet-core / spreadsheet-renderers
  • @nop-chaos/report-designer-core / report-designer-renderers

Integrated workspace configuration (tsconfig references, path aliases, Vite aliases), fixed runtime/test issues, ensured all tests pass.

3.8 testid and Architecture Consistency

On 03-29, added the testid field to BaseSchema, propagated through the compilation→parsing pipeline, all production renderers apply data-testid to the root element. On the same day, completed an architecture consistency audit, discovering issues such as implicit layout injection by renderers, validation trigger semantic drift, theme token naming drift, etc., and established a two-phase fix strategy.

Key paths: packages/ui/src/, docs/architecture/styling-system.md, packages/flux-react/src/field-frame.tsx, packages/spreadsheet-renderers/src/, packages/report-designer-renderers/src/


4. Phase 4: Complex Renderers and Architecture Audit

Time: 2026-03-28 ~ 2026-03-31

4.1 Full shadcn/ui Migration

On 03-28, completed the full migration of the shadcn/ui component library. The @nop-chaos/ui package expanded to cover the full suite of components including Inputs/fields, Overlay, Layout/feedback, etc. Flow Designer, form renderers, code editor, etc., fully switched to shadcn/ui components.

4.2 Code Editor Package

On 03-30, @nop-chaos/flux-code-editor was created based on CodeMirror 6, unifying the expression editor and SQL editor. Features include: support for 8 languages, expression/SQL completion, expression validation, friendly name tagging, template mode, fullscreen toggle, light/dark themes. Subsequently on 03-31, SQL enhancements (formatting, snippet templates, variable panel, SQL execution result preview) were completed.

4.3 Condition Builder

On 03-30, a complete condition-builder renderer was implemented in flux-renderers-form, supporting embedded/selector mode, AND/OR/NOT logic, field search, grouping, unique fields, nested groups, custom operators.

4.4 Word Editor Package

On 03-31, @nop-chaos/word-editor-core (framework-agnostic bridge layer with zero React dependencies + Store) and @nop-chaos/word-editor-renderers (EditorCanvas, RibbonToolbar, FontControls, WordEditorPage) were created. Integrated @hufe921/canvas-editor as the canvas rendering engine, with template expressions stored as hyperlinks. On the same day, completed Phase 1 basic editor integration and Phase 1~4 toolbar controls.

4.5 Architecture Audit

On 03-31, conducted a comprehensive audit of core packages (flux-core, flux-runtime, flux-react, flux-formula, 3 renderer packages), analyzing approximately 32,000 lines of non-test source code. Findings: flux-core's design is correct (it is a base package containing shared pure utilities, not a pure types package), form-runtime has been decomposed into 10 sub-modules, and the dependency flow is clean.

Key paths: packages/ui/src/, packages/flux-code-editor/src/, packages/word-editor-core/src/


5. Phase 5: Code Audit and Quality Convergence

Time: 2026-04-01 ~ 2026-04-03

5.1 Code Audit Fix Plan (Plan #25)

Executed 14 fixes covering 8 packages:

  • Build hygiene: Removed stale tsconfig include paths, created scripts/verify-no-src-artifacts.mjs CI guard
  • Logical correctness: Fixed Flow Designer allowMultiEdge logic error, unified executeApiObject() request pipeline
  • Defensive fixes: Wrapped NodeRenderer with React.memo, added boundary protection for evaluateArray/evaluateObject
  • Performance optimizations: API cache LRU eviction, Proxy cache WeakMap

5.2 Comprehensive Code Overhaul (Plan #27)

Executed comprehensive code overhaul including:

  • Render phase remains side-effect free
  • Form path state relatedPaths fix
  • Extracted shared hook for form field controller
  • Dynamic renderer API payload validation
  • Changed root component registry from module-level mutable state to instance-level state
  • Added change detection to ScopeRef.merge() method

5.3 Data Source Redesign

DataSourceSchema removed the body region, instead injecting data into the current scope. If dataPath is set, the response is written to scope[dataPath]; otherwise, the response is merged as a plain object into the current scope.

5.4 useOwnScopeSelector Dual Hooks and Full Adoption of @nop-chaos/ui

On 04-03, flux-react exposed useOwnScopeSelector() in parallel with the lexical useScopeSelector(). Report Designer shell renderers migrated to the own-scope hook, consuming only fragment host data. On the same day, completed adoption migration of word-editor-renderers, report-designer-renderers, spreadsheet-renderers to @nop-chaos/ui.

5.5 Dependency and Lint Upgrades

From 04-02 to 04-03, the workspace upgraded to eslint-plugin-react-hooks recommended-latest strict rule set (later deepened on 04-16 to React 19 strict lint baseline), completed Lucide React patch fixes, and cleaned up all build artifact leaks in src/ directories.

Key paths: packages/flux-runtime/src/request-runtime.ts, packages/flux-renderers-data/src/data-source-renderer.tsx, scripts/verify-no-src-artifacts.mjs


6. Phase 6: Runtime Architecture Convergence and Performance Optimization

Time: 2026-04-04 ~ 2026-04-06

6.1 Formily Comparative Analysis and Performance Direction

Completed a detailed comparison with 10+ low-code platforms (AMIS, Formily, LowCode Engine, Appsmith, ToolJet, Retool, etc.). Core findings:

  • The reactivity model is the most critical shortcoming: The current Pull Model triggers evaluation of O(number of nodes × number of expressions) on parent scope changes, whereas Formily's Push Model is O(number of dependents)
  • Flux's AOT compilation, orthogonal scope design, and field metadata-driven compilation are unique architectural advantages
  • Decision: Maintain Flux's compile-first general-purpose platform baseline, allowing only thin local capability extensions in the form subdomain

6.2 Dependency Tracking and Change Path Notification

Implemented ScopeChange dependency tracking baseline:

  • ScopeStore carries ScopeChange (set of changed paths)
  • Formula leaf evaluation refreshes dependency set after each successful run
  • NodeRenderer subscriptions gate metadata/property recomputation through dependency path intersection
  • Later evolved into lexical root binding model: dependency tracking converges to lexical roots like user, row, record

6.3 Source Registry and Reaction Runtime

  • Source Registry (source-registry.ts): RendererRuntime exposes registerDataSource(...), sources are bucketed by ScopeRef.id, the data-source renderer is only responsible for registration/release lifecycle
  • Reaction Runtime (reaction-runtime.ts): ReactionSchema supports watch, when, immediate, debounce, once, reaction execution async scheduling occurs after writes stabilize
  • Self-cascade protection: Queued reaction triggers merge change paths by pending turn, self-cascading reactions hard-stop after a limited number of times

6.4 Action Control Flow Extensions

The action system added when/parallel/timeout/retry:

  • when: Precondition check, returns structured skip result if false
  • parallel: Promise.all parallel execution
  • timeout: Structured timeout result, cancelable request-like actions participate in actual cancellation
  • retry: Retry strategy with fixed attempts/fixed delay

6.5 Complex Renderer State Ownership

On 04-05, the Table renderer introduced a local/controlled two-level state ownership model, extended to three levels on 04-06 with the addition of scope mode:

  • local (default) — internal renderer state
  • controlled — external schema/runtime driven
  • scope (added 04-06) — reads/writes reactive state directly from the current rendering scope

6.6 Frontend Programming Model Documentation

docs/architecture/frontend-programming-model.md was established as the top-level architecture baseline document, defining Flux's seven core primitives (at that time the first primitive was still called Base Tree, officially renamed to Template on 04-21). The seven primitives are: Template (formerly Base Tree), ScopeRef, Value, Resource, Reaction, Capability, Host Projection.

6.7 WorkbenchShell Extraction

On 04-04, extracted the shared WorkbenchShell React component from various designers into packages/flux-react/src/workbench/. The page renderers of Flow Designer and Report Designer migrated from handwritten three-column layouts to the unified WorkbenchShell. Shell is purely presentational, carrying no Flux scope or domain knowledge.

Key paths: packages/flux-runtime/src/source-registry.ts, packages/flux-runtime/src/reaction-runtime.ts, packages/flux-runtime/src/action-runtime.ts, packages/flux-react/src/workbench/workbench-shell.tsx, docs/architecture/frontend-programming-model.md


7. Phase 7: Frontend Programming Model Finalization and In-depth Design

Time: 2026-04-06 ~ 2026-04-11

Note: This phase had parallel work with Phase 8 (Template Instantiation), with overlapping dates.

7.1 Programming Model Evolution Discussions

After multiple rounds of in-depth discussions (8 rounds of discussion recorded in docs/discussions/2026-04-06-programming-model-optimality-critique.md), finally established:

  • Keep the seven primitives closed, do not introduce an alternative primitive system
  • Understand data-source as "registering a named dynamic value into scope"
  • name as the sole normalized publication path, mergeToScope: true as the only special publication mode
  • Action semantics (when + then + onError + parallel) already form a DAG at execution time
  • Distinguish between "progressive authoring surface" and "DAG execution semantics"

7.2 Action/API Convergence Construction

  • Renamed declarative request from ApiObject to ApiSchema
  • type: 'source' as an action-based anonymous value consumption form
  • data-source as the named/dispatch extension of source
  • Standardized built-in action naming to camelCase (openDialog, showToast)

7.3 Validation System In-depth Design

On 04-11, completed a unified validation design (docs/analysis/2026-04-11-flux-validation-unified-design.md), covering:

  • modelGeneration counter to track validation model replacements
  • Async run identity quintuple (ownerId, modelGeneration, path, ruleId, runGeneration)
  • Two lifecycle paths: owner-compatible model refresh vs. owner boundary change
  • State retention rules: always reset materialized caches and async runs

7.4 Form Linkage and Hidden Field Policy

On 04-11, fully implemented the HiddenFieldPolicy contract (Plan 67): clearValueWhenHidden, validatePath skipping, notifyFieldHidden, 21 new tests.
Constraint-based declarative linkage (xui:linkage) compiled into existing node metadata/properties and validation flow.
Field presentation snapshot (effectiveDisabled/effectiveRequired).

7.5 Owner Status Model

On 04-09, unified loading/pending/status as owner-specific read-only summaries:

  • Internal form expressions standardized to $form binding
  • Cross-form observers standardized to explicit statusPath
  • Surface owners (dialog/drawer) expose external read-only status via statusPath

7.6 Component Documentation System and xui:imports Expression Projection

On 04-07, established the docs/components/ component documentation system, each component directory carries design.md + example.json, distinguishing registered renderers from planned renderers. Component naming standardized to Flux native vocabulary rather than AMIS legacy names.

On the same day, completed xui:imports expression projection; import aliases can now be used in expressions as $alias.method(...), sharing the same import namespace provider mapping as the existing namespace:method action dispatch.

Key paths: docs/architecture/frontend-programming-model.md, docs/architecture/api-data-source.md, docs/architecture/action-scope-and-imports.md


8. Phase 8: Template Instantiation and Node Identity System

Time: 2026-04-07 ~ 2026-04-08

8.1 Template Instantiation Architecture

docs/architecture/template-instantiation-and-node-identity.md established the architecture of "compile the template once, instantiate it multiple times at runtime":

  • cid is strictly a mount-time active node bridge ID
  • Structure resolution belongs to the runtime-owned resolver
  • Canonical runtime address as NodeLocator = runtimeId + templateGraphId + templateNodeId + instancePath

8.2 Repeated Instance Identity Propagation

Table row child rendering (cell, buttons, expanded) passes in [{ repeatedTemplateId: 'table.row', instanceKey: rowKey }], row child debug locator data can now see the real instancePath.

8.3 NodeRenderer Compatibility Migration

Through Plan 40, gradually migrated CompiledSchemaNode dependencies to NodeInstance/templateNode:

  • NodeFrameWrapper consumes templateNode + explicit renderer wrap metadata
  • RendererComponentProps and useCurrentNodeMeta() mirror templateNode + optional locator
  • Fragment/dialog ownership seams migrated to active-node-first fallback

8.4 Compiler-Integrated Diagnostics

Plan 41 implemented compiler-integrated schema diagnostics:

  • flux-core exposes a formal schema diagnostic contract
  • CompileSchemaOptions carries diagnostic/validation policy
  • RendererDefinition can contribute schemaValidator
  • Form and table renderers contributed renderer-owned schema validator checks

8.5 BEM Migration Completed

All internal __ markers cleaned up, field framework, code editor, spreadsheet/report designer, workbench areas migrated to data-slot/data-*.

Key paths: docs/architecture/template-instantiation-and-node-identity.md, packages/flux-react/src/node-instance.ts, packages/flux-runtime/src/node-resolver.ts


9. Phase 9: Deep Audit, Performance Optimization, and Architecture Convergence

Time: 2026-04-12 ~ 2026-04-20

Note: This phase was the highest-density convergence period of the entire project, with code changes, document audits, performance optimizations, and architectural decisions densely interwoven.

9.1 Architecture Document Consistency Audit and Governance System Maturation

On 04-12, completed the first full-scope architecture document consistency audit, checking all files under docs/architecture/ for consistency with code and with each other. Discovered cross-document conflicts (Final Execution Schema wording, node identity model, xui:imports boundaries, style contract drift, etc.), established a repair strategy sharded by document family.

This phase also marked the formal maturation of Flux's unique development governance method:

  • First write owner doc (target state architecture document)
  • Then write execution plan
  • Write daily log after execution
  • Finally use an independent sub-audit to confirm closure

Many subsequent Plans (73~121) followed this method.

9.2 Plan 82: Architecture Contract Implementation Convergence

Plan 82 was the core convergence plan from 04-12 to 04-14, covering multiple parallel contract alignment threads:

  • xui:imports node lifecycle tightening (Phase 5): The creation of ActionScope for import declaration nodes and namespace registration began to separate from renderer policies; module loading deduplication and scope namespace lifecycle initially became independent. The final import-owned boundary was finalized in Plan 133 on 04-23 (see Phase 10, 10.3)
  • Surface family extraction (Phase 5): dialog/drawer state extracted from page.store into independent SurfaceStore, SurfaceRuntime became the unified owner for dialog/drawer/surface
  • Value adaptation contract convergence (Phase 6): detail-field, detail-view, object-field, array-field, variant-field gradually aligned to shared value-adaptation helper and unified scope model
  • Architecture narrowing decision: After multiple rounds of implementation attempts, the architecture documentation clearly positioned object-field, array-field, variant-field as inline live-edit controls (editing directly writes to parent form), only detail-field/detail-view retain staged owner semantics (confirm/cancel boundaries)

9.3 ScopeRef Read-Write Separation and Per-Path Subscription

From 04-14 to 04-15, performed a major refactoring of ScopeRef's core APIs:

  • read()readVisible() + materializeVisible() (Plan 89): readVisible() uses the prototype chain to provide a lazy lexical view; materializeVisible() is called only at explicit flattening boundaries (formula broad-access, debugger dump, request includeScope: '*')
  • Per-path fine-grained subscription (Plan 90): FormStore added a subscribeToPath(path) mechanism; keystrokes on field A no longer wake subscribers of field B, achieving O(1) field-level invalidation
  • Host Projection scope base (Plan 87): RendererRuntime.createHostProjectionScope(...) moved the read-only/write-protection boundary of host projection from React hooks into a shared runtime contract

9.4 Performance Optimization Series (Plans 100~110)

On 04-16, executed an entire performance optimization plan series, from audit to per-package implementation:

  • Playground loading and bundle boundaries (Plan 102)
  • Flux React hot path fixes (Plan 103): NodeRenderer useSyncExternalStore selector stabilization, ClassAliasesContext broadcast debouncing
  • Formula runtime hot path (Plan 104)
  • Spreadsheet performance and virtualization (Plan 105): setCells() batch operations, grid virtualization (binary search for visible range), requestAnimationFrame batch selection/fill/zoom
  • Runtime and form invalidation performance (Plan 106): parallel field validation, computeScopeState caching, publishStatus skip unchanged updates
  • Collection renderer scalability (Plan 107): table viewport-driven virtualization (threshold 50 rows, overscan 10), row scope cache changed from full clone to in-place mutation + generation counter
  • Form field consumer performance (Plan 108): useBoundFieldValue() uses UNUSED_VALUE sentinel selector to avoid inactive subscriptions
  • Flow Designer performance hygiene (Plan 109): node synchronization reduced from O(n²) to O(n)
  • API request and cache hygiene (Plan 110): source refresh O(1) name indexing, polling changed from setInterval to setTimeout chain

9.5 @nop-chaos/flux-renderers-form-advanced Split

On 04-16, split 11 advanced renderers from flux-renderers-form (~15,800 lines) into the new @nop-chaos/flux-renderers-form-advanced package: condition-builder, variant-field, detail-view, detail-field, object-field, array-field, array-editor, tag-list, key-value, etc. flux-renderers-form was reduced to ~3,000 lines. Dependency direction confirmed as form-advanced → form → basic (no cycles).

9.6 Capability Projection Manifest

On 04-16, introduced the Capability Projection Manifest architecture (Plan 112), upgrading host protocols from runtime wiring conventions to compile-time visible and verifiable static contracts:

  • HostCapabilityProjectionManifest declares host projection fields and namespaced capability methods
  • RendererDefinition.hostContract lets renderer definitions carry host contract metadata
  • Flow Designer as the first pilot, declaring 30 designer:* methods
  • Compiler-integrated diagnostics: validateActionShape() can now validate host action parameter shapes

9.7 @nop-chaos/flux-i18n Internationalization Package

On 04-17, created the @nop-chaos/flux-i18n package, based on i18next and react-i18next, supporting zh-CN (default) and en-US. All translation keys use the flux. prefix. Subsequently migrated hardcoded strings from packages like condition-builder, report-designer, code-editor, form-advanced to t() calls, upgrading the ESLint i18next/no-literal-string rule from warn to error, ensuring that new hardcoded strings cause build failures.

9.8 ValueAdapter Unified Protocol

On 04-20, docs/architecture/value-adaptation-and-detail-field.md established ValueAdapter as the canonical shared protocol (Plan 121):

  • Simple fields use declarative adapters: stringAdapter(), booleanStringAdapter(), array adapters
  • Composite owners (object-field, variant-field) uniformly connect to actionAdapter() for transformInAction / transformOutAction
  • Staged helpers of detail-field/detail-view internally delegate to actionAdapter(), keeping the public API unchanged
  • ValueAdapter becomes the standard access method for new value-oriented fields, replacing JSX local type conversions

9.9 CompiledSchemaNode Complete Elimination

On 04-16, the compilation pipeline no longer passes through the CompiledSchemaNode intermediate layer, directly generating TemplateNode from SchemaInput. CompiledSchemaMeta and CompiledNodeRuntimeState were demoted to type aliases. This cleanup simplified the compilation pipeline and eliminated an indirection layer that no longer held value after the template/instance separation landed.

9.10 Renderers Contract Unified Static Metadata

On 04-20 (Plan 117), added unified static contract fields to RendererDefinition: rendererClass, rendererTraits, propContracts, eventContracts, componentCapabilityContracts, scopeExportContracts. propContracts immediately participates in compiler unknown attribute checking; the remaining fields are reserved for tooling (Inspector, online editor). button, form, crud, designer-page served as the first pilots.

9.11 Action Pre-compilation and Async Governance

On 04-20 (Plans 119~120), pushed the action system into the compile phase:

  • CompiledActionProgram IR: compileAction() compiles ActionSchema to CompiledActionProgram/CompiledActionNode; the runtime executor no longer mixes raw schema execution paths internally
  • Async governance convergence: Shared async-governance.ts base unified the run identity, stale publish gating, and debug diagnostics for three categories of async runtime owners: data-source, reaction, and async validation

9.12 Documentation Governance and Deep Audits

From 04-12 to 04-19, multiple rounds of deep audits were produced (12 audit dimensions covering API surface, state ownership, reactivity precision, async safety, validation consistency, renderer contracts, style compliance, field slot modeling, lifecycle, etc.). After each audit, only true defects still reproducible in the current code were fixed, avoiding over-fixing.

Key paths: packages/flux-core/src/value-adapter.ts, packages/flux-runtime/src/async-governance.ts, packages/flux-runtime/src/action-compiler.ts, packages/flux-i18n/src/, packages/flux-renderers-form-advanced/


10. Phase 10: Compiler Independence and Package Boundary Hardening

Time: 2026-04-21 ~ 2026-04-25

10.1 Compiler Package Extraction

Extracted the @nop-chaos/flux-compiler package from flux-runtime:

  • Schema compilation/validation
  • Action pre-compilation
  • Compilation symbol table
  • Diagnostics and validation lowering
  • flux-runtime briefly retained a compatibility re-export layer (removed in Plan 124 on 04-22; runtime side no longer holds any compiler code)

10.2 Action Core Package Extraction

On 04-22, further extracted the @nop-chaos/flux-action-core package from flux-runtime, with ActionRuntimeAdapter becoming the unified action invocation boundary. By this step, Flux completed a three-layer split:

  • flux-compiler responsible for "turning schema into executable artifacts"
  • flux-action-core responsible for "action dispatching, control flow, and unified invocation exit"
  • flux-runtime responsible for "connecting compiled artifacts with the host environment and holding lifecycle"

10.3 Import Boundary Semantic Convergence

On 04-23, the creation of ActionScope for xui:imports was separated from renderer policy into import-owned boundary semantics (Plan 133). Module loading deduplication and scope namespace registration operate independently; import lifecycle and compile-time diagnostics participate in the compilation pipeline, completing the second phase of the ActionScope / xui:imports model proposed in late March.

On the same day, Plan 132 eliminated runtime fallback reads of raw Schema objects — DataSource and Reaction fully migrated to compiled data; the runtime no longer holds uncompiled schemas. This is a direct manifestation of the compile-forward mainline.

10.4 Base Tree → Template Renaming

On 04-21, the first primitive of the programming model was renamed from Base Tree to Template, emphasizing its nature as a compile-time immutable program definition. SchemaCompiler produces an immutable TemplateNode graph; the runtime only consumes and instantiates.

10.5 Data Domain Owner Architecture

On 04-22, the Data Domain Owner concept was formally elevated to an architecture baseline document (docs/architecture/data-domain-owner.md). object-field, array-field, variant-field aligned to the Data Domain Owner baseline — composite fields become explicit data domain owners, with clear value adaptation, validation coordination, and sub-scope lifecycle. This complements the staged owner semantics of detail-field/detail-view: two ownership models (inline live-edit vs. staged confirm/cancel boundaries) cover all composite field paradigms.

10.6 DingFlow Tree Mode

Introduced a structured process tree contract: nodes can have branch groups, branches implicitly merge, continuation flow enters the downstream child of the owner node. In tree mode, free connections, free reconnections, and manual node dragging are disabled.

10.7 CRUD Contract Finalization and Shared Context Menu

The design and implementation of CRUD spanned multiple phases: component contract document completed on 04-12 (docs/components/crud/design.md), entered implementation around 04-17, and completed interaction and contract finalization on 04-24 ~ 04-25:

  • CRUD selection summary and refresh behavior stabilized
  • Spreadsheet shared context menu baseline (copy, cut, paste, clear, insert/delete rows/columns)
  • Double-click fill handle uses adjacent data region for auto-fill down

On 04-25, Plan 139 removed the DataSourceSchema.api field; all remote calls are uniformly dispatched via { action: 'ajax', args: ... }. ApiSchema is explicitly defined as a transport contract used internally by the ajax action; author side no longer directly touches independent API definitions — the convergence from independent execution paths to unified action dispatch is completed here.

Key paths: packages/flux-compiler/src/, packages/flux-action-core/src/, docs/architecture/flux-runtime-module-boundaries.md, docs/architecture/capability-projection-manifest.md


11. Phase 11: Comprehensive Quality Convergence and Host Maturity

Time: 2026-04-25 ~ 2026-05-03

Note: This phase was the second high-density convergence period after Phase 9 (04-12~04-20), but the focus shifted from "architecture contract alignment" to "comprehensive quality convergence" — performance audit, test institutionalization, adversarial security review, validation owner boundary precision, host tooling engineering. If Phase 9 answered "is the architecture right?", Phase 11 answered "is the implementation robust enough".

11a. Performance Audit and Hot Path Optimization (04-26)

Conducted in-depth performance audits on four hot paths: runtime, form, spreadsheet, report-designer:

  • Eliminated JSON.stringify full-value comparisons: Form valuesPath publication used JSON.stringify for change detection, incurring significant serialization overhead in high-field-count forms. Replaced with path-aware structural comparison.
  • Spreadsheet batch writes: Batch operations like paste/cut changed from per-cell full Map cloning to setCells() batch interface, eliminating O(n) immutable clone overhead.
  • Condition-builder recursive structural equality: Condition builder used JSON.stringify for value comparison; replaced with recursive structural equality function, avoiding stringification overhead and key-order sensitivity.
  • Path-aware form value subscription: useCurrentFormState added an optional { path: name } parameter; field-level subscribers are woken only when the specified path changes, eliminating cascading re-renders of unrelated fields.
  • Full adoption in advanced form renderers: Path-aware subscription extended to all advanced form renderers including object-field, array-field, detail-field, variant-field, array-editor, key-value, etc.

11b. Test Coverage Institutionalization and Deep Audit (04-26 ~ 04-27)

Plan 143: Coverage threshold institutionalization

Enforced 80% Vitest coverage thresholds in all core package configurations. Systematically closed coverage gaps in the following packages:

  • flux-runtime, flux-react, flux-renderers-data
  • flux-renderers-form, flux-renderers-form-advanced, flux-renderers-basic
  • flux-formula

First 18-dimensional deep audit (04-27)

Full-dimensional audit covering 24 packages, discovering 1 P0, 16 P1, 28 P2, 36 P3 issues. Audit dimensions included:

  • Architecture consistency, state ownership, async safety, reactivity precision
  • Host contracts, test quality, accessibility, security
  • Performance, boundary clarity, dependency direction, API surface stability
  • Documentation synchronization, type safety, error handling, internationalization, observability, extensibility

11c. Renderer Contract and Host Projection Convergence (04-26 ~ 04-30)

Plan 145: runtime/react/renderer hot spot boundary convergence

Extracted shared helper functions, established projected-owner scope base, CRUD owner bridging, Flow Designer page-shell/adapter split. Cross-package dependencies in renderer hot paths converged to explicit contracts.

Plan 146: Domain-host projection and lexical convergence

  • Word Editor real-time save vs. auto-save timing semantics clarified
  • Report Designer standardized selection vocabulary
  • Host projection interfaces of various domain designers aligned to a unified baseline

Plan 144: Execution boundary diagnostics and host contract tooling

  • Diagnostic information carries source location, supporting precise jumping from runtime errors to schema definition locations
  • Host contract manifest tooling, supporting automated contract checking

Plan 150: xui:actions — Schema-local named action chains

Introduced the xui:actions attribute, allowing declaration of named action chains on schema nodes:

  • __xui_actions__ synthetic namespace carries schema-local action definitions
  • Lexical inheritance: child nodes inherit xui:actions from the parent scope, sharing the same namespace resolution mechanism as xui:imports
  • Action chains support when/then/onError control flow

11d. Adversarial Review and Security Hardening (05-01 ~ 05-02)

Conducted an adversarial review of the entire codebase (24 packages), covering compiler-runtime contract consistency, reaction cascade depth, scope dangerous key filtering, formula parser/evaluator depth limits, form validation resilience, accessibility.

Key fixes:

  • $Date symbol table fix: Completed from 7 methods to 14 methods, covering all date operations
  • booleanStringAdapter("false") fix: Boolean("false") pitfall — the string "false" is truthy in JavaScript; adapter must explicitly parse
  • Action compilation depth limit: MAX_ACTION_COMPILE_DEPTH=128 to prevent malicious nested action chains from causing compile stack overflow
  • Scope snapshot sanitization: sanitizeSnapshot() blocks prototype pollution keys like __proto__, constructor, prototype
  • Formula parser depth limit: MAX_PARSER_DEPTH=256, MAX_EVAL_DEPTH=256 to prevent deeply nested expression attacks

11e. Validation Owner Boundary Convergence (04-30 ~ 05-03)

The validation owner boundary underwent three stages of precision refinement, finally forming a clear ownership hierarchy:

Plan 157: validation owner boundary

  • formId becomes a true targeting carrier, no longer just an identifier
  • submitWhenHidden semantics removed — submission behavior of hidden fields is uniformly controlled by the owner
  • Registration identity maintains path-singleton: registrations on the same path are automatically replaced, no duplication

Plan 163: core boundary

  • flux-core completely removes React type dependencies, becoming a pure TypeScript package
  • flux-react owns the reactComponent convenience path
  • Surface runtime creates an independent validation owner for each surface, achieving validation isolation

Plan 168: validation owner convergence

  • formId resolution path unified
  • validateOn: 'change' no longer gates on touched — validation on change, orthogonal to touched state
  • Summary-gate enforcement during submission: collect all validation summaries on submit, block until all pass

Plan 174: Strict Validation Mode

Schema authors can enable strict compilation mode, causing the compiler to report unknown attributes. This mechanism fills the last piece of schema validation: from "compiler ignores unknown attributes" to "unknown attributes are compile errors in strict mode".

Final Validation Owner Hierarchy:

Owner Level Coverage Typical Scenario
form All fields within the form Main form submission
page-root Page-level validation Page-level linkage constraints
surface Independent validation domain within dialog/drawer Popup form independent submission
detail-child Sub-validation domain within staged owner Detail row edit confirm/cancel boundary

11f. Host Tooling and Engineering (04-30)

Turborepo introduction

Turborepo as the workspace task runner, enabling parallel execution of build/typecheck/test/lint. The task dependency graph is automatically topologically sorted by Turborepo, eliminating manual orchestration scripts.

Repository-level audit toolchain

  • dependency-cruiser: Dependency direction validation, preventing circular dependencies and illegal cross-layer references
  • knip: Dead code detection, identifying unused exports, types, and dependencies
  • Stryker: Mutation testing pilot, validating the effectiveness of test suites
  • Semgrep: Static security scanning, detecting known unsafe patterns

Bundle analysis

Support for pnpm analyze via rollup-plugin-visualizer, visualizing bundle composition of each package, helping identify size regressions and unexpected dependencies.

Key paths: packages/flux-runtime/src/form-runtime.ts, packages/spreadsheet-core/src/, packages/flux-formula/src/, packages/flux-core/src/, docs/plans/143-*, docs/plans/145-*, docs/plans/157-*, docs/plans/163-*, docs/plans/168-*


12. Key Principles of Architectural Evolution

Looking across the evolution history from 2026-03-20 to 2026-05-03, the following principles repeatedly appear in key decisions:

12.1 Compile First

Flux always does as much work as possible at compile time: value classification, expression compilation, action pre-compilation, schema diagnostics. The runtime only executes compiled artifacts and makes no additional judgments. This principle runs from the five node types of CompiledValueNode through the TemplateNode/NodeInstance separation.

12.2 Data and Capability Separation

ScopeRef purely carries data, ActionScope purely carries capabilities; they are orthogonally separated. This decision avoids turning ScopeRef into a general-purpose method registry, keeping the scope model simple.

12.3 Renderer Contract Consistency

All renderers follow the unified RendererComponentProps pattern, with data coming from props.props/props.meta/props.regions/props.events/props.helpers, and do not directly access stores. This ensures renderer replaceability and testability.

12.4 Marker Classes Carry No Styling

Layout renderers only emit semantic marker classes (nop-container, nop-flex); marker classes carry no visual styling. All spacing/direction/padding is explicitly declared via classAliases or semantic attributes in the schema. This avoids implicit layout and style drift.

12.5 Domain Bridge Pattern

Complex designers (Flow Designer, Report Designer, Spreadsheet) are integrated via the DomainBridge pattern: core packages provide pure logic runtime, renderer packages provide React integration, and the canvas is decoupled via bridge callbacks. This allows canvas implementations to be replaced without affecting core logic.

12.6 Documentation as Architecture

From the layered documentation system of Flow Designer to multiple rounds of discussion on the frontend programming model, the Flux project always uses documentation as the carrier of architectural decisions. The separation of target state and snapshot state, and the separation of discussion records from normative documents, ensure the sustainable maintenance of architectural knowledge.

12.7 AI-First Observability

The debugger was designed as AI-first from the start: structured automation APIs, diagnostic reports, session export, interaction tracing. Subsequent dependency tracking change paths, source/reaction registry snapshots, and node locator identity all follow the "machine-readable over human-readable" observability design.

12.8 Design First, Implementation Approximates

Flux's core design ideas (Env environment abstraction, Api/Resource as asynchronous reactive values, lexical scope data chain, xui:imports action modularization, declarative first) were established as early as the AMIS theory research phase. The architectural evolution records not the discovery of design directions, but the gradual approximation of implementation precision to design principles — from runtime interpretation to compile-time staticization, from implicit conventions to explicit contracts, from monolithic to layered package boundaries.

12.9 Host Boundary Testing Ground

Flow Designer is the first testing ground for Flux to validate host protocols. What Flux learned from Flow Designer is not "how to make a flowchart editor", but that complex controls must access the runtime via host boundaries, namespaced actions, bridge snapshots, and configuration-driven approaches. The same unified runtime later successfully accommodated two vastly different complex host paradigms: structured process tree (DingFlow) and Excel-native workbench (Spreadsheet/Report Designer).

12.10 Implementation-Driven Convergence

Although design ideas were established early, the implementation path was not achieved overnight. Flux's architecture gradually became precise through continuous implementation, failure, regression, splitting, renaming, rewriting documentation, and then being forced to converge by sub-audits. Each step of implementation advancement was accompanied by clear documentation and regression test coverage, ensuring traceability of implementation decisions.

12.11 Audit Rule Extraction Forms Long-Term Governance Loop

From the deep audits of Phase 9 to the 18-dimensional audit of Phase 11, the Flux project continuously distilled audit findings into reusable governance rules: coverage thresholds (Plan 143), compilation depth limits, scope snapshot sanitization, strict validation mode. The output of each audit is not just fixes, but the extraction of new rules. These rules are written into code (threshold configs, compiler checks) rather than documentation, forming an automated governance loop.

12.12 Adversarial Review Complements Deep Audit

Deep audits discover problems from architectural dimensions (state ownership, dependency direction, contract consistency); adversarial reviews expose vulnerabilities from an attacker's perspective (prototype pollution, deep nesting, truthy traps). The two complement each other: deep audits ensure "architecture is correct", adversarial reviews ensure "attacks do not succeed". Phase 11 institutionalized both as standard processes before release.

12.13 Reactive Subscription Precision is an Architectural Concern

From per-path subscription (Plan 90) in Phase 9 to path-aware useCurrentFormState in Phase 11, subscription precision has always been an architectural concern, not a local optimization. The wake-up scope of React re-renders directly determines the responsiveness performance of forms, tables, and designers. Flux's answer is progressive precision from full-value comparison → dependency path intersection → path-aware precise subscription; each step is an architectural decision, not an implementation detail.

12.14 Validation Owner Hierarchy

The ownership of the validation system is not a binary "has/has not", but a hierarchical model: form (form domain) → page-root (page domain) → surface (popup domain) → detail-child (staged sub-domain). Each layer has an independent lifecycle, submission gating, and validation summary. This hierarchy was the result of three Plans (157 → 163 → 168) gradually converging in Phase 11, evolving from implicit "form owns all validation" to an explicit four-layer ownership model.


13. Appendix: Timeline Overview

Phase Date Key Events
Phase 1 03-20 ~ 03-23 Bug #1~#5 analysis and fixes, debugger birth, ActionScope/Import semantics established, Flow Designer packages created, canvas bridge initial implementation
Phase 2 03-23 ~ 03-27 Canvas bridge, command adapter, schema-driven designer, production-grade visual alignment
Phase 3 03-25 ~ 03-29 AMIS→Flux renaming, flux-core split, styling system, shadcn/ui migration, FieldFrame, Report/Spreadsheet migration, testid
Phase 4 03-28 ~ 03-31 Full shadcn/ui migration, Code Editor, Condition Builder, Word Editor, architecture audit
Phase 5 04-01 ~ 04-03 Code audit fixes, comprehensive overhaul, data source redesign, dual-hook design, full @nop-chaos/ui adoption
Phase 6 04-04 ~ 04-06 Formily comparison, dependency tracking, source registry, reaction runtime, action control flow, WorkbenchShell, table state ownership, programming model doc
Phase 7 04-06 ~ 04-11 Programming model finalization, Action/API convergence, Owner Status, component documentation system, imports expression projection, validation design, HiddenFieldPolicy
Phase 8 04-07 ~ 04-08 Template instantiation, repeated instance identity, NodeRenderer migration, compiler diagnostics, BEM cleanup
Phase 9 04-12 ~ 04-20 Deep audit, architecture doc consistency, Plan 82 contract convergence, ScopeRef read-write separation, per-path subscription, performance optimization series (Plans 100~110), form-advanced split, Capability Projection Manifest, flux-i18n, ValueAdapter unified protocol, CompiledSchemaNode elimination, action pre-compilation IR, async governance convergence
Phase 10 04-21 ~ 04-25 Compiler package extraction, action core package extraction, Import Boundary convergence, Base Tree→Template, DingFlow tree mode, CRUD, shared context menu
Phase 11 04-25 ~ 05-03 Performance audit and hot path optimization, test coverage institutionalization (Plan 143), 18-dimensional deep audit, renderer contract convergence (Plans 145/146/144), xui:actions (Plan 150), adversarial security review and hardening, validation owner four-layer boundary convergence (Plans 157/163/168), Strict Validation Mode (Plan 174), Turborepo engineering

Conclusion

The architectural evolution of NOP Chaos Flux is a process of systematically implementing established design ideas on a modern technology stack. The core designs — Env environment abstraction, Api/Resource as asynchronous reactive values, lexical scope data chain, xui:imports action modularization, declarative first — were established as early as the AMIS theory research phase (see c:/can/nop/nop-entropy/docs/theory/amis/). What Flux did was not to invent these principles, but to solve the structural limitations of AMIS at the schema layer (parallel field explosion) and runtime layer (MST tight coupling), and to implement these principles in a compile-first, type-safe, package-boundary-clear manner.

The strongest mainline throughout the evolution is from runtime interpretation to compile-time execution: value classification, template instantiation, action pre-compilation, host contract staticization, compiler package extraction — each step is a milestone on the same path of moving runtime judgment forward to compile time. But this mainline is not the only one. Running in parallel and equally important are two others: the ownership convergence of owner / validation / surface (from implicit dual-state to explicit staged owner, finally converging to the four-layer validation owner of form / page-root / surface / detail-child), and the boundary explicitization of host contract / import boundary / capability manifest (from runtime wiring conventions to compile-time visible contracts). The final three-layer split of flux-compiler / flux-action-core / flux-runtime is the physical form of the compile-forward mainline. Phase 11 built on the three-layer split to complete comprehensive quality convergence: performance hot path optimization, 80% coverage institutionalization, adversarial security review, validation owner boundary precision, host tooling engineering — a leap from "architecture correct" to "implementation robust".

The resulting architecture — DSL-first + compilation/execution separation + orthogonal scopes + template instantiation + domain bridging + compile-time host contracts + layered validation owner + automated quality governance — provides a clear modern runtime reference for declarative frontend low-code DSLs.


nop-chaos-flux is open source:

Top comments (0)