2b7e4ba250780869cb26b9276a7f1028841b3482
6 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
2b7e4ba250 |
spec: dreaming is ambient, not scheduled — a brain has no cron job
El SDK CI - dev / build-and-test (pull_request) Failing after 11m59s
Corrects the section I was most confident in, which is usually the tell. The previous draft had dreaming as "offline replay, decoupled from input, a mode the system enters when it is not acting." That is SLEEP. Daydreaming is dreaming, and it runs all day: the default mode network is anticorrelated with task engagement, activating hundreds of times a day for seconds at a time, doing the same work — recombination, simulation, autobiographical integration. Insight arrives in the shower, not at the desk, because that is abduction completing during ambient recombination. Sleep is the DEEP case, not the case: no input competing, no task claiming capacity, so recombination runs further. Same process, different depth, not a different mode. Consolidation is what happens with the capacity that is not claimed. Two consequences the draft had backwards: The launch-agent fragments are wrong in KIND, not merely in number. 23:55 / 06:00 / 08:30 implements dreaming as a scheduled batch when it should be ambient. A brain has no cron job. A ticker is a supervisor deciding from outside when a thing should happen — the same failure mode as inventing an owner for ownership and a grounder for grounding, wearing a scheduler. THE PRESENCE OF A TICKER IS THE DIAGNOSTIC: every StartInterval, every Hour/Minute, every POST-to-beat marks a place where an intrinsic rhythm was replaced by an external clock. And soul.el's continuous awareness_run() beside the HTTP workers is the CORRECT shape, not the offender. Ambient consolidation in the gaps is exactly daydreaming. It was the only fragment shaped right, running on a broken foundation: shared mutable state with no owner and six other systems dreaming into the same graph. The previous draft condemned the right behaviour because of the substrate under it. So the crash restates once more: not "read paths mutate the index" (mechanism), not "duplicate canonical state" (structure), and not "one system dreamt while awake" — but seven systems dreaming into one graph with no owner for dreaming. Contention was the symptom of the missing owner. Sequencing step 1 inverts accordingly: soul's loop is the shape the others fold INTO, not something to remove. Step 2 becomes "no tickers, no cron." |
||
|
|
6c670c18ce |
spec: grounding is a two-axis gradient, and decisions carry their provenance
El SDK CI - dev / build-and-test (pull_request) Failing after 4m33s
Rewrite. The earlier draft got the root right and everything downstream of it wrong. Corrections, in the order they were forced: keystone_write_blocked is not a protection requirement. "Keystone" means load-bearing, not precious: the self anchor is the REFERENCE FRAME every other stance calibrates against. If it calibrates from the measurements it is used to judge, the ruler fits the readings, everything corresponds forever, and drift becomes undetectable from inside. That is circular calibration — the same defect as #147's circular grounding, one level up. The block is the right requirement implemented as a prohibition, which is why it still costs everything §0 says it costs. The fix is provenance separation (evidence not downstream of itself), not a flag. Corruption requires mutation and the engram does not mutate, so four of the five requirements previously decomposed out of "protect the identity region" are satisfied by the substrate: recoverability, governance, evidence quality and rate are all free. Authorization is the only residue and is bounded — an unauthorized writer can propose, never erase. General law: in an immutable substrate, any mechanism that refuses a write is either redundant with immutability or an epistemic constraint misfiled as a protective one. Grounding is two-dimensional. Everything consumed is grounded factually AND relationally, and a claim can be factually grounded but relationally wrong — the evidence holds, the meaning does not. A scalar cannot represent that quadrant, and assert gates on one floor, so a well-evidenced claim is licensed regardless of whether it means the right thing. Live instance: conscience-substrate has the Child's Companion hard bell contacting 911 and CPS — factually defensible, relationally wrong against never-auto-contact. Grounding is a gradient, not a score: direction says what would have to change. Two gradients in one space, and the ANGLE between them is the meaning — factually-true-relationally-wrong becomes measurable instead of requiring a careful reader. It decays on the dynamics already present for memory (base_level, temporal_decay_rate, access ring, BLL), which mechanizes "never leave stale canonicals" so it stops depending on vigilance. Computed continuously, recorded only on SIGNIFICANT movement, old never leaves. Persisting every recomputation would make reads write — the exact eg_vindex_sync defect. Significance is defined by consequence (crossing a floor, flipping factual/relational sign, reversing direction), never by an epsilon. The supersession chain is then the trajectory, a derivative obtained free from immutability, and abduction fires on the trajectory rather than on a reading. What it is all for: for any decision, reconstruct what the grounding was at that moment and what the relationship was between fact and values at that moment. That distinguishes WRONG THEN from WRONG SINCE, which is otherwise impossible, and it is structurally anti-rationalization — the old grounding never leaves and the values frame does not fit to outcomes, so a decision cannot be made to look justified after the fact. Also records: assert returns "still_held": true HARDCODED — a temporal property named in the API and answered without consulting anything, the same shape as magnitude:1 beside a zero vector. And states plainly that #147 is the wrong shape: it fixed a scalar's honesty rather than replacing the scalar. |
||
|
|
d0e9af0f6f |
spec: correspondence and censorship — the root beneath the day's defects
El SDK CI - dev / build-and-test (pull_request) Failing after 13m29s
Effect: all five cognitive faculties return byte-identical results, differing only in their label. The Ishikawa converges on a root one level above the faculty design: things are permitted to be exempt from correspondence, and exemption is censorship. A region forbidden to learn is forbidden to be grounded, and a region that cannot be grounded cannot be asserted, corrected, OR vindicated. The loss is symmetric — censorship does not preserve a true belief, it makes the belief's truth value permanently unknowable. keystone_write_blocked is therefore not a safety mechanism. Self is a crystallized relational neighbourhood, not a stored document; a region exempt from calibration reintroduces the stored document as a feature. reduction_pct = 0.00 on the identity region is the strongest abduction signal in the system and the current response is to suppress it. The protection it reached for already exists and is better: the beat is supersede-not-mutate, so immutability is what makes learning safe. The faculties are not one operation with parameters. They differ by what each may change: reason changes the estimate (a read), induce changes the parameters (the correspondence-beat, which already exists and measurably works at 28.11% Brier reduction), abduce changes the structure (a WRITE the current signature cannot express, since engram_think returns a GeoGradient). Abduction is not selected by a caller — it is triggered by residual that parameter adjustment cannot absorb, and proposes a candidate hub held as a hypothesis until grounded. Also records the no-exemption invariants generalised from the day's fixes (#141 #142 #143 #146 #147 #148), each of which was a specific correspondence forbidden from occurring, and the application to the crisis surface: a censored safety model cannot tell a real crisis from a false positive, because the feedback is exactly what has been censored. Measured vs inferred is labelled throughout. The claim that the self region's zero grounding is CAUSED by the block is explicitly marked inferred — the comparison node also has zero, and isolating it requires removing the block and observing whether grounding then accrues. |
||
|
|
8ae163e8e5 |
lang: give cross-cutting concerns an owner instead of a convention
El's units of encapsulation are the function and the module. Neither can hold
a concern that belongs to the process, so each one had been expressed the only
way it could be -- as a convention: call this at every site. Conventions of
that shape do not hold. Measured here: zero process-identity guards at any
layer, 20 environment variables each with its default written inline at the
read site, 62 persist call sites, 10 per-route auth checks. One absence, four
times.
Step 0 first, because the premise was wrong. El was believed to have no
middleware or effect mechanism. It has one, and it is already load-bearing:
codegen injects engram_boundary_beat at the entry of every @manager/@accessor
fn, decorators take arguments and stack, dharma_emit from a non-@manager fn is
a #error, and the cgi block injects el_cgi_init at the head of main(). So the
correct move was not to invent a mechanism but to generalize the seam that
already existed. The real gap is narrower and is now recorded: the seam is
prologue-only and its callee is a fixed builtin.
Adds a `program` block -- the third program-level declarative block. cgi and
service declare what a program may do; program declares what it is.
program "engram" {
singleton: "engram"
env ENGRAM_BIND: String = ":8742"
env GUIDE_PORT: Int = "8771"
}
singleton takes an exclusive flock before any user statement runs and refuses a
second start, reporting the holder's pid. It is a lock rather than a pidfile so
the kernel releases it on death including SIGKILL -- no stale state, and so no
"delete the lock file to get unstuck" ritual, which would itself be a
convention. It reports the pid because "already running" is not actionable; a
pid is. That is the direct answer to a stale process surviving a pkill and
going on answering probes.
env entries resolve once at startup -- environment wins, declaration supplies
the fallback -- and validate as a whole, reporting every problem at once rather
than costing one restart per variable. config("X") for an undeclared X is
fatal, because an advisory schema is just another convention. Programs without
a program block are unaffected, so migration is per-program.
Only one keyword is added. `config` and `env` could not become keywords -- both
are real identifiers in the tree -- so the block's fields are read as
identifier token values by its own parse loop and stay usable everywhere else.
The init function is emitted at the block site and called from main() rather
than inlined into main(). The live backend is codegen_streaming, which emits in
source order and cannot hold the entry list alive until main(); this way only a
single bool has to survive.
Also fixes: config() was defined in el_runtime.c but never prototyped in
el_runtime.h, so any el program calling it failed to compile under C99.
Spec: section 18 documents what shipped. Section 9 is corrected -- it claimed
decorators had no structural meaning, which has not been true for some time.
Section 19 designs durability-as-an-epilogue-effect and route authorization
and states plainly why neither is implemented here: both land in files under
concurrent modification, and the prerequisite for both is lifting the seam
from prologue-only to prologue/epilogue.
Self-hosting fixpoint verified byte-identical.
|
||
|
|
8e9d88fc01 |
runtime: publish the vector index instead of guarding it
El SDK CI - dev / build-and-test (pull_request) Failing after 10m59s
The crash (SIGTRAP in engram_activate -> eg_vindex_sync -> vindex_insert -> _realloc) had three read paths mutating five process-global statics. engram_activate, eg_knn_for_node (whose own comment says "No writes.") and engram_geo_reify_run_json all called eg_vindex_sync, which frees the index, reallocs the seen-map and inserts — on a read. Three moves, in decreasing order of how much they dissolve: 1. Misfiled scratch is not shared state. visited/visit_epoch/visited_cap were never owned by the index; they are one traversal's local, hoisted into struct VIndex as an allocation optimisation. They want neither a lock nor a capability nor a pool — just to go back in the call frame. Two concurrent READS stomped each other purely because of this. 2. const IS the capability. Once the scratch leaves the struct, search reads and nothing else, so vindex_search takes a const VIndex*. That is exactly what a capability-pointer ABI would have bought — a read path physically cannot call vindex_insert, enforced by the compiler on every future caller — for one qualifier instead of an ABI swept across hundreds of builtins. 3. What survives is publication, not ownership. HNSW insert is NOT an append: it rewires the neighbour links of already-existing elements and reallocs elems[], so the store's append-only property does not transfer to the index derived from it. eg_vindex_sync therefore splits into eg_vindex_maintain (exclusive, sole mutator) and eg_vindex_view (shared, returns const VIndex*). A read path may demand that a current snapshot exist — a request to the owner, not a mutation by the reader. Write-side owner: eg_vindex_note_embedded hooks the embedding-ASSIGNMENT sites rather than the append sites, because a node with no embedding cannot be in a vector index — embedding assignment is the event that owns index membership. One O(log n) insert, no O(node_count) presence scan. This also retires the "STALENESS (honest tradeoff)" note where a lazily-embedded older node stayed invisible to route_nearest/autoconnect until a full rebuild (the embed-gap #20 shape). Evidence. The existing harness conflated two hazards, which is why fixing half of it read as failure. Split into four: single (3000 vec, ASan+UBSan) clean -> clean readers (4 readers, no writer, TSan) RACE -> clean unsynchronized (writer+reader, bare) race -> race, expected forever published (owner + 4 readers) n/a -> clean, 3000/3000 landed RESULT: PASS. recall@10 = 0.9365 at ef_search=128 (gate >= 0.90); determinism byte-identical across two independent builds. The unsynchronized half is now permanently expected to race, deliberately: it is the executable proof that the boundary must live above the data structure, not inside it. fb32d15's guard is KEPT, correcting this design's own section 5. Measured, it guards TWO structures and only one was converted here: g->nodes/g->edges are realloc'd in place (el_runtime.c:7618,7629) and engram_activate_inner's embed-backfill writes n->emb through exactly such a borrowed pointer. Deleting the guard reintroduces a measured 11171->9579 edge loss. Its comment is narrowed to the RAM graph and the deletion precondition named. That corrects the ordering claim too: the residual is not one ABI that dissolves everything at once, it is a PROPERTY applied per structure. Residues evaporate in the order the property is applied, and a residue whose structure has not been converted must be left standing. |
||
|
|
1ae68962cf | restructure: move el compiler content into lang/ |