Last updated: 2026-09-26
Abstraction: Inducing Categories, Trust-Gated
Abstraction watches the same firehose of Short Term content that every other component draws on, and does one specific job with it: it induces general categories from repeated entity/intent pairs, then answers a standing question — categorize(entity) — with whichever induced category currently accepts that entity, or "unknown" if none does. What makes it more than a lookup table is where the categories come from and who is allowed to add one.
One mechanism, two edges Ephemeral / ToolingKnowledge that evolves in months to a year — check for updates
Abstraction's induction step is not bespoke logic. It calls the same rule_add/solve synthesis engine (F:/patlang/self_hosting/lib/synthesis.patlang) that Procedural Memory uses for a different purpose elsewhere in this architecture — one mechanism serving two edges of the system, per the architecture document. In components/abstraction.patlang, a category is registered as a fact-and-rule pair against a first-mentioned entity and an intent, and categorize walks the list of known categories asking solve(category, [synth_ground(entity)]) until one succeeds.
The comment at the top of the source file is explicit about a limitation this induces: the engine is existence-based, not frequency-weighted. A fact either exists in the store or it doesn't, so calling the synthesis step on an identical example twice changes nothing. That rules out the obvious implementation of "weight admission by trust" — you cannot make a fact "more true" by repeating it. Abstraction handles this honestly rather than faking a repeat-count scheme against a mechanism that wouldn't respond to one: trust is applied as a binary admission threshold. An example is admitted once, in full, or not admitted at all.no partial credit, admit or reject only
The gate itself Applied / MethodologicalKnowledge with a 5–10 year half-life — stable practice
Every incoming percept carries an interlocutor. Abstraction asks lib/trust_calculus.patlang's tc_score_for(interlocutor) for that interlocutor's current trust score and compares it against abstraction_admission_threshold(), fixed at 0.15. Trust itself is not a single number kept in the interlocutor's head; it's a three-component vector [T_positive, T_negative, T_uncertainty], persisted to disk so a restarted Abstraction instance doesn't forget who it has learned to distrust. The update rule tc_update nudges the positive component up by alpha = 0.1 on a positive event and the negative component up by beta = 0.3 on a negative one — trust builds slowly and is damaged quickly, the asymmetry the trust-calculus page this code implements argues for. The score handed to Abstraction is clamp01(pos - neg), floored at zero rather than going negative.
Below the threshold, the example is not silently dropped — it is consumed off the queue and acknowledged, logged via cc_log_decision as not admitted, but it never reaches rule_add at all. A zero-history interlocutor's very first example is therefore always rejected outright: an unseen interlocutor starts at [0, 0, 1], giving a trust score of exactly 0, below the 0.15 bar. One exception is deliberate: tc_bootstrap_interlocutor() ("system_bootstrap") starts at [1, 0, 0] — fully trusted from the outset, standing in for pre-vetted, developer-supplied seed examples rather than an open interlocutor that has to earn its way in.trust starts at zero, not neutral
features/trust_calculus.feature exercises this directly: an unseen interlocutor scores 0; three positive events bring a score close to 0.3; a single subsequent negative event drops the score by more than one positive event's worth, confirming the build-slowly/damage-quickly asymmetry rather than just asserting it. features/abstraction.feature then closes the loop end to end — a percept about "Paris" with intent "travel" from a trust-cleared "trusted_user" gets admitted, and categorizing "Paris" subsequently returns "travel"; the same percept about "Berlin" from a zero-history "new_user" is rejected, and categorizing "Berlin" returns "unknown".
Freeze, checkpoint, rollback — and an honest limit on rollback Applied / MethodologicalKnowledge with a 5–10 year half-life — stable practice
Abstraction can be frozen (freeze_compilation/resume_compilation): while frozen, new examples are logged as not-admitted regardless of trust, but categorize keeps answering from whatever was already compiled — a human reviewer can halt further learning without taking the component's existing knowledge offline. It also supports checkpoint and rollback against its persisted examples file. The source comments are candid about a constraint here: PatLang's rule_add has no corresponding retract. A fact already registered in a live process's fact store cannot be un-registered from that same process, so a rollback rewrites the file on disk correctly but only takes full effect once the component restarts and indstore_replay rebuilds the fact store fresh from the rolled-back file — the same rebuild step an ordinary restart already performs. The rollback handler therefore replies and then calls component_request_stop() itself, so the fix is a brief, self-contained restart rather than a claim of instantaneous retraction it can't actually deliver.no true undo, only a restart
Feeding back into Perception Ephemeral / ToolingKnowledge that evolves in months to a year — check for updates
Every admission also publishes to the schema-feedback channel (lib/schema_feedback.patlang), a plain-text line like "schema: entities like 'Paris' tend to have intent 'travel'". Perception instances only ever peek at this topic — never consume it — so several Perception instances can each read the same accumulated schema expectations without racing each other to claim entries away. This is the concrete shape of "Abstraction feeds back into Perception as schema-driven expectation" from the requirements spec, and it is the same channel that Self-Model's transparent mode reuses for its own predictions, discussed on that page.
Like every long-running component in this codebase, Abstraction composes lib/component_base.patlang rather than inheriting a base class — PatLang's signal handlers don't support per-instance dispatch, so shared lifecycle (status queries, a quit handler, periodic re-announcement for dashboard discovery) is reused via included modules. That machinery is exercised generically in features/component_lifecycle.feature, not reproduced per component.
See also
Abstraction's output feeds Representation (via the schema-driven expectation loop back through Perception) and gates what Imagination is allowed to recombine — only episodes whose entity currently categorizes as known are eligible. For the fuller architectural picture of how these components fit together, see the architecture page. Abstraction is the slow, general-structure-extracting half of the same fast/slow split How Sleep Turns Ephemeral Memory Into Foundational Knowledge describes for a human learner's neocortex. The parallel has a limit. That page's human mechanism strengthens a memory gradually with each spaced, effortful retrieval, while Abstraction's induction is existence-based and admits an example once or not at all, as noted above. The trust gate does the safety job repetition-based strengthening would otherwise do; it does not reproduce spacing or retrieval practice as a mechanism.