Most coding agents reconstruct the architecture from scratch every run. They reread the repo, guess what must stay true, then edit files. Tomorrow the same prompt can invent a slightly different “must not change.” embabel-dif is a prototype that moves that knowledge out of the prompt and onto Embabel’s blackboard.
It is not Merly’s proprietary Deterministic Intent Folding algorithm. It is an experiment inspired by the public DIF idea: interpret with an LLM, then fold accepted facts into a stable semantic model that a deterministic planner can actually use.
LLM = probabilistic interpreter / generator
DIF = semantic intent substrate
Embabel = deterministic planner / orchestrator
Verifier = deterministic acceptance boundary
The problem the loop keeps hiding
A typical agent loop is: request → LLM reads the repo → LLM infers intent → LLM edits code → tests. The semantic model is implicit. On the next run the model may reconstruct a different answer to:
- why a component exists
- which behavior is architectural, not incidental
- which tests express real intent
- which earlier decisions still constrain this change
The prototype splits a change into three layers and tries to keep the first two independent of whatever syntax the LLM eventually writes:
INTENT What should be true?
Refresh tokens rotate. Google login stays.
SEMANTICS What properties follow?
A used refresh token cannot authenticate again.
sessionToken remains in the JWT.
SYNTAX Which files implement that?
TokenService.java, a migration, an IT.
What “folding” means here
Folding is not a novel math algorithm. After candidate facts are accepted, deterministic rules normalize, deduplicate, derive invariants, relate them to evidence, and refuse to plan if two required intents conflict.
Four observations about sessionToken — a test, a mobile reader, a commit, and the user’s “do not change login” — fold into one invariant: preserve the sessionToken claim. Unfold it later and you still have the explanation.
Milestone 1 is already a GOAP path
The first milestone stops before anyone writes code. The question is: can probabilistically extracted intent become stable typed state that Embabel’s planner can reason over?
ChangeRequest
│ interpret (fixture, or LLM for unknown wording)
▼
CandidateIntent
│ fold (deterministic)
▼
SemanticModel
│ analyze repo evidence
▼
RepositoryAnalysis
│ derive missing obligations
▼
VerificationPlan
DifEmbabelAgent is a normal annotation agent. Interpret, fold, and analyze are @Action methods. Planning verification is the goal, but only when noBlockingIntentConflicts is true. GOAP picks the sequence from types, not from a hardcoded script.
The known refresh-token wording is handled by FixtureIntentInterpreter, so ./mvnw test and the shell fold command do not need an API key. Other requests go through LlmIntentInterpreter.
./mvnw test
./scripts/shell.sh
fold # Embabel invocation → VerificationPlan
fold-local # folder only, no planner
intent-diff # semantic git-diff
x "Add refresh-token rotation without changing existing login behavior."
The first scenario: rotate, do not break login
The request is deliberately narrow:
Add refresh-token rotation without changing existing login behavior.
The fixture already knows Google and Apple OAuth exist, authorization-code flow is in use, JWTs carry sessionToken, login ITs exist, and refresh tokens are still reusable. The folder turns that into five intents and the matching invariants: consumed tokens cannot be reused; Google, Apple, and authorization-code clients still authenticate; sessionToken stays compatible.
Absence reasoning is the interesting extra. Rotation implies a token family id, consumed-token state, replay detection, and a rotation integration test. The fixture repo already has the first three. The deriver emits one MissingObligation: rotation integration test. That is a typed fact the planner can act on later — not a sentence buried in a prompt.
If someone also requires “existing clients must reuse the same refresh token indefinitely,” ConflictDetector marks the pair mutually exclusive. Embabel will not plan implementation while that conflict is unresolved.
A semantic diff is more useful than a file diff
Before vs desired for this scenario is a property snapshot, not a patch:
SEMANTIC DIFF
+ refresh-token.rotates=true
- refresh-token.reusable=true
UNCHANGED:
= jwt.claim.sessionToken=present
= provider.APPLE=present
= provider.GOOGLE=present
RESULT: PASS
The verifier’s job is not “LLM, does this look correct?” It asks whether required properties were preserved. Code and test checks are still stubbed; the semantic diff already works.
What is stubbed on purpose
| Phase | Status |
|---|---|
| 1. Typed model + fold | Working |
| 2. Embabel GOAP → VerificationPlan | Working (fixture path, no LLM) |
| 3. LLM code generation | Stub (LaterPhaseActions) |
| 4. Deterministic verification | Semantic diff works; code/test checks stubbed |
| 5. Repair from VerificationFailure | Types only |
6. Persistent .dif/ memory |
Seed YAML + write-snapshot stub |
Phase 3–5 stay off the GOAP graph on purpose so milestone 1 cannot accidentally wander into “generate a PR.” Seed files under .dif/intents, invariants, evidence, and relations are versioned with the repo — the start of architectural memory that an agent can inspect instead of reconstructing.
Why Embabel is the right control plane
Embabel does not duplicate the semantic layer. It consumes typed objects — ChangeRequest, CandidateIntent, SemanticModel, MissingObligation, later VerificationFailure — and decides the next legal action. That is the same type-is-wiring model as the rest of the framework: return a new object, flip a condition, replan.
The long-term bet is domain maturity. While the domain is unknown, an LLM explores. Once a fact is accepted, it should migrate into typed knowledge, deterministic planning, and deterministic verification. Git already stores what changed. A DIF-style layer stores why, what must remain true, and what depends on it.
Source: github.com/jmjava/embabel-dif
Spec: DIF_EMBABEL_PROTOTYPE.md
Related: Embabel Agent Framework · embabel-v1-learning · refresh-token-research
No comments:
Post a Comment