Sign in

    This version of the module is deprecated: WRONG MODULE NAME

    maked_moonbit

    MAKED on MoonBit: rabbita SPA frontend + a Flask-style micro-framework on moonback

    web
    rabbita
    moonback
    sqlite
    Download zip
    Author
    Version
    0.1.4
    License
    Apache-2.0
    Last updated
    5 days ago
    Downloads
    4

    #MAKED on MoonBit

    A recursively self-evolving modelling framework — designed around an adversarial knowledge loop.

    Current release: v0.1.4 — published as riantr/maked_moonbit on mooncakes.io.

    MAKED is a five-domain recursive cognitive architecture: Model → Data → Experience → Attack → Knowledge forms a closed ring, each domain being the adversarial overcoming of the one before it. The system drives state transitions through its own cycle — from arxiv research papers, to causal inference, to the pyroduct state machine — forming a self-driving closed loop of knowledge evolution.

    Technical implementation: rabbita single-page frontend + a Flask-style micro-framework backend on moonback, with SQLite storage. The state machine is riantr/pyroduct@0.1.31, which also supplies the English rendering (en_label / en_gloss / en_designation) that every user-visible string here comes from.

    #Core Concepts

    #The Five-Domain Ring (M → D → E → A → K)

    LetterDomainPyroduct PositionDrive SlotStructural Relation
    MModelStandingderived from the tablethe model stands, one foot in the past and one in the future
    DDataEncounterderived from the tablethe model's inescapable encounter with the other (data)
    EExperienceHonorderived from the tableexperience absorbed as a reward bestowed by the idol
    AAttackEvilderived from the tableattack as the hard, cold thing that contracts the horizon
    KKnowledgeDisciplinederived from the tableknowledge distilled by enduring and clearing the reefs

    The ring order M → D → E → A → K is the path the logo draws clockwise, not the alphabetical order of the names.

    #The Three-Layer State Machine

    1. Subject layer: every domain owns an independent pyroduct state machine (34 positions × 8 slots × 53 transitions)
    2. Group layer: group states that coordinate across domains (Scattered → Converging → Common Tongue → Settled, 20 states)
    3. Society layer: not yet implemented

    Flexible starting point: the loop may start at any domain (Model by default); switch the starting domain with POST /api/loop/reset/:domain. Each domain's state machine initialises independently — only the current pointer changes.

    #Drive Slots Come from the Transition Table, Not from Semantics

    Which slots can actually push a given position is answered by the pyroduct transition table: exitable_slots lists the slots that have an outgoing edge from that position, and drive_slot prefers one among them that genuinely moves. Of the 272 = 34 × 8 combinations, 228 are Block — no way out.

    This rule was forced by measurement. Earlier, each domain hard-coded one "semantically corresponding" drive slot (Model meets data → Co-being); the five slots that came out of that had not one outgoing edge in the transition table: stepping the loop 18 times in a row left all five domains' positions completely unchanged, while the next_domain ring pointer rotated as usual and the page looked perfectly normal.

    The behaviour now:

    SituationBehaviour
    The table has a Moved outgoing edgeTake it; drive_slot reports the concrete slot
    Only Held / Same outgoing edgesRecord them faithfully; the position does not move and the cursor does not advance
    Only Open outgoing edgesundecided: true, listing the candidates, does not choose for the subject
    No outgoing edge at allblocked: true, drive_slot is the empty string

    The ring order M → D → E → A → K → M is kept as the presentation order — it is the order the logo draws and the way the site narrates itself; but it is no longer treated as evidence that the state machine moved.

    #The Adversarial Knowledge Loop

    The key difference from a traditional data pipeline: the Attack domain. The model is not "fed" by data, it is "forged" by attack. Research papers are mapped onto pyroduct triggers by keyword heuristics, driving state machine transitions; DoubleML causal inference estimates the causal effect of a paper's "novelty" on its "influence".

    #Quick Start

    .\build.ps1 moon run --release --target native cmd/server

    build.ps1 builds the browser bundle, stages it to the backend's serving location, type-checks the backend, runs all tests, and builds the server. The backend serves both the JSON API and the frontend static files, so there is no second web server and no CORS configuration.

    #Environment Variables

    VariableDefaultMeaning
    MAKED_PORT8080listen port
    MAKED_DBmaked.dbSQLite file path
    MAKED_DISTfrontend/distfrontend build output directory

    #API

    #Pages and Domains

    RouteReturns
    GET /api/statusdatabase path, page count, the five domains
    GET /api/pagesall pages (sorted by sort)
    GET /api/pages/:sluga single page, or 404
    GET /api/domainsthe five domains (ring order)

    #State Loop

    RouteReturns
    GET /api/loop/statuscurrent domain, position, history, domain states, group state, mode
    GET /api/loop/slotsthe eight drive slots (two-character designation + English + gloss)
    GET /api/loop/modethe current mode (structured/free)
    POST /api/loop/stepadvance one ring step (using the current domain's default drive slot)
    POST /api/loop/step/:slotadvance one ring step (using a named slot, English or two-character designation)
    POST /api/loop/resetreset to the initial state
    POST /api/loop/reset/:domainreset with the given domain as the starting point (accepts a letter or the English name)
    POST /api/loop/mode/:modeswitch mode (structured/free)
    GET /api/loop/continuations?depth=Nthe model's own "all possible continuations" (after_open)

    Besides the original fields, GET /api/loop/status also returns drive_slot_name, blocked, undecided, open_slots (the slots that really have an outgoing edge at the current position, with their outcomes), and at_anchor / drivable for each domain.

    /api/loop/continuations is built on pyroduct's after_open — the transition table's own answer to "all possible continuations", as distinct from expand, which requires the caller to name a slot sequence up front. It lists only edges that really exist and does not choose for the subject: when the same position is reachable by several routes it is listed once at the shortest distance, and the slot-grouped view is where the alternative routes become visible.

    #Loop Modes

    • Structured mode: follows the ring order M→D→E→A→K, uses the designated drive slot for each domain, and always advances to the next domain after a step
    • Free mode: driven by any slot, exploring the state space; it stays in the current domain when the outcome is Block ("no way out"), otherwise it advances

    Structured mode is the default. Free mode allows exploring transition paths through the pyroduct state space that do not follow the ring order.

    #Research Loop

    RouteReturns
    GET /api/research/papersarxiv SNN papers + trigger mapping
    POST /api/research/drivefetch papers and drive the loop
    GET /api/research/causalDoubleML causal inference results

    #Project Structure

    backend/ micro-framework, storage layer, API routes, state loop engine app.mbt App: route table + ordered middleware chain request.mbt Request wrapper response.mbt Response value and dispatch database.mbt SQLite storage layer pages.mbt content model + nine pages of seed data api.mbt JSON API routes loop.mbt five-domain ring loop engine (subject + group state machines) research.mbt arxiv research paper fetching and trigger mapping causal.mbt DoubleML causal inference maked_app.mbt assembly, static files, SPA fallback frontend/ rabbita single-page application app.mbt state machine and router views.mbt header, domain cards, page rendering logo.mbt five-ring mark (SVG) loop_state.mbt loop state visualisation page.mbt typed accessors for the backend JSON cmd/server/ native entry point cmd/web/ js entry point (browser bundle) tools/ CI and test tooling ci.sh CI pipeline (15 gates)

    #CI Pipeline

    bash ci.sh # all 15 gates bash ci.sh --quick # skip the slow gates bash ci.sh --unit-only # type check + unit tests only

    There is no bash on this Windows machine, so ci.sh cannot be run locally; the parts that can be reproduced locally are covered by .\build.ps1 (bundle → check → backend tests → frontend tests → server build). Of the 15 gates, 9 exist only as a shell implementation and cannot be reproduced locally.

    #Mutation Checks

    Beyond the mutation gate inside bash ci.sh, there are three scans that can be run separately:

    .\tools\mutate-backend.ps1 # 11 mutations, 0 survived, 1 expected-equivalent .\tools\mutate-frontend.ps1 # 15 mutations, 0 survived .\tools\mutate-loop.ps1 # 14 mutations, 0 survived, 1 expected-equivalent

    That one EQUIV in mutate-loop is deliberate: measurement shows that all 34 positions do have outgoing edges, so the None branch of drive_slot is currently unreachable. It stays in the roster on purpose — if the transition table ever gains a genuinely dead position, it will flip to KILLED, and that is exactly the signal we want.

    GateToolWhat it checks
    native-checkmoon check --target nativebackend type safety
    js-checkmoon check --target jsfrontend type safety
    fmtmoon fmt --checkcode formatting
    treemoon treedependency audit
    unit-nativemoon test --target native120 backend tests
    unit-jsmoon test --target js12 frontend tests
    coveragemoon test --enable-coveragecoverage
    benchmoon benchbenchmarks
    provemoon proveformal verification (Why3)
    bddbdd_test.mbt14 Given/When/Then scenarios
    contractcontract-test.sh46 API contract assertions
    componentcomponent-test.sh6 cross-module integration checks
    sastsast-check.sh11 static security checks
    mutationmutation-test.sh10 mutation tests (80% kill rate)
    dastdast-check.sh5 dynamic security checks

    #Request Handling

    Three layers, outside in:

    1. static_files: serves real files from frontend/dist
    2. spa_fallback: an unmatched browser navigation returns index.html (so /about cold-loads correctly)
    3. the router: serves /api/..., everything else returns a JSON 404

    The fallback excludes /api/ paths. A final segment containing a dot is treated as an asset (a missing stylesheet returns 404 rather than HTML). A route conflict aborts startup (fail, not raise).

    #The Two Initial Fetches Are Chained, Not Batched

    init issues one request (GET /api/pages). The loop status (GET /api/loop/status) is requested from the Loaded handler, after the first response has already arrived.

    Batching the two with @cmd.batch looks equivalent and is not. With the batch, every click-initiated POST still reached the server and still changed state, but no response ever came back: Step, Reset and the slot buttons all mutated the backend while the view stayed frozen on stale data, with no error shown anywhere. Chaining the second request restores them.

    The cause was not root-caused — the same build works when the init issues a GET and a POST, and fails when it issues two GETs, which points at how two concurrent requests are dispatched rather than at anything in the loop engine. The safe rule to preserve: issue the two initial fetches one after the other. Re-batching them is a silent regression that no unit test catches.

    #SQLite Storage Layer

    Three key behaviours (verified, not assumed):

    1. prepare only compiles, it does not execute. A statement that was never stepped is silently dropped by finalize — DDL goes through exec
    2. A finished statement must be reset before it can be reused. bind overwrites the bindings in place
    3. finalize reports the error code of the most recent evaluation — a failed step poisons the following finalize

    #Release Conventions

    • Patch version progression: v0.1.x (no minor releases unless specified)
    • Gitee for day-to-day storage, GitHub for releases
    • Run bash ci.sh and get an all-green result before releasing

    #License

    Apache-2.0