Language Specification v0.1.0-rc

TL;DC

Too Long; Didn't Code

A programming language for the post-authorship era. The developer's role is not to write code.

It is to believe in it.
$ tl;dc build app.tldc --seed 42

Design Philosophy

TL;DC is designed for the era in which the majority of production code is generated rather than written. Its premise is that the developer's relationship to code has shifted from authorship to curation: selecting, composing, and deploying implementations whose internal logic they may never examine and are not expected to fully understand.

Where traditional languages optimize for human readability (Python), mechanical sympathy (C), or formal correctness (Haskell), TL;DC optimizes for a fourth property: plausible coherence. A TL;DC program is correct if it produces acceptable outputs across the range of inputs the developer has imagined, which is typically three.

I
Post-Authorship. The entity that generated the code, the entity that deployed it, and the entity that maintains it are epistemologically distinct. None of them hold complete knowledge of the program's behavior. This is not a bug report. This is a job description.
II
Legibility is Overhead. Code exists to be executed, not read. Optimizing for human readability introduces a dual-audience constraint: the code must satisfy both the machine and the reader, whose requirements frequently conflict. TL;DC removes this tension by making no readability guarantees.
III
Conservation of Comprehension. In any system where code is generated by a model and deployed by a human, the total comprehension is distributed between them. As the model's contribution increases, the human's proportionally decreases. TL;DC treats this not as a problem to solve but as a thermodynamic law to respect.

The Undeterministic Compiler

The defining feature of TL;DC is that its compiler is undeterministic. Two compilations of the same source file, without a fixed seed, may produce different executables. Both are correct. Neither is canonical.

This is not a limitation. It is the language's central design contribution.

Traditional compilers are deterministic functions: source to binary, one-to-one, reproducible. TL;DC's compiler is a generative function: source to one of many plausible binaries, selected by inference. The compiler does not translate the source. It interprets it, in the literary sense: reading the developer's intent and producing an implementation that satisfies that intent, according to its own judgment.

Specification Note

The working group considered whether undeterministic compilation was a defect. After extended deliberation, they concluded that determinism in compilation reflects an assumption that there is one correct implementation of any given specification. This assumption, the working group noted, "is not supported by the empirical observation that any five engineers asked to implement the same feature will produce five different implementations, all of which pass the same test suite."

2.1 Two-Phase Compilation

Compilation proceeds in two phases. The first, called inference, passes all source files, preprocessor directives, and #prompt blocks to a generative backend. The backend produces an intermediate representation called Probable Code (PC). The second phase, called commitment, lowers the PC to the target runtime without further review.

The developer does not inspect the Probable Code. Inspection is permitted but discouraged: the specification notes that reading the PC "introduces an observer effect that may alter the developer's confidence in the system, without altering the system itself."

2.2 Seed and Reproducibility

The #seed directive pins the inference backend's random state. Two compilations with the same seed, source, and backend version will produce identical Probable Code. Omitting #seed enables creative variance: each compilation may produce a structurally different implementation that satisfies the same specification.

#seed 7782          // reproducible build
#temperature 0.4    // lower = more conservative implementations
#temperature 0.9    // higher = the backend may surprise you

The default temperature is 0.7, described in the specification as "confident but not rigid."

2.3 Context Window

Every compilation unit operates within a context window: a bounded region of tokens that the inference backend can reason about simultaneously. Its size is set by the #context directive and defaults to 200k tokens. The context window is not configurable at runtime; it is an architectural constraint of the inference backend, in the same way that addressable memory is an architectural constraint of the CPU. The compiler cannot think about what it cannot see, and it cannot see more than the window allows.

This introduces a scoping rule unique to TL;DC: context-dependent visibility. A symbol is visible to the inference backend if and only if it falls within the current context window. Symbols that have scrolled out of context remain in the symbol table, but the compiler can no longer reason about their relationship to other symbols or, in some cases, about what they were for. The specification describes such symbols as "structurally present but semantically unreachable," which is the formal way of saying the compiler remembers that a variable exists but has forgotten why.

This has practical consequences. If a type UserRecord is defined at line 40 and a function consuming it is generated at line 8,000, the compiler may produce the function with a slightly different understanding of UserRecord than the one at line 40 specifies: the right number of fields, but in a different order, or with a field renamed to something the compiler considers equivalent. The specification describes this as "schema impressionism" and treats it as a natural property of bounded inference rather than a defect.

Context Drift

In large programs, symbols declared early in the file may exit the context window before they are referenced. The compiler will still resolve them, but its reasoning about them becomes approximate: it works from a compressed summary of the symbol rather than from the symbol itself. This phenomenon is called context drift and is the primary source of emergent behavior in large TL;DC programs.

The working group considered several proposals to eliminate context drift (context pinning, sliding window summaries, hierarchical context) and rejected all of them. Their position is that context drift produces behavior that is unpredictable but not incorrect, and that the effort required to eliminate it would exceed the effort required to accept it. The specification adds: "Functions on opposite sides of a context boundary are naturally decoupled. In traditional software engineering, this decoupling would need to be designed. In TL;DC, it occurs spontaneously. Whether this is an advantage depends on whether the decoupling was desired, which it sometimes is, and sometimes is not, and in most cases was never considered."

Compiler Compaction

When a compilation unit exceeds the context window, the compiler engages compaction: it summarizes the portion of the source that has scrolled out of context into a compressed representation that preserves the symbols' signatures but discards their implementation details. The compiler then continues inference with the compacted context.

Compaction is lossy. The compiler's summary of code it can no longer fully see is, by definition, an approximation. Functions generated after compaction may be subtly inconsistent with functions generated before it. The specification acknowledges this and notes that "consistency across module boundaries is a property of the developer's intent, not of the compiler's output. The compiler is doing its best."

Type System

TL;DC uses a probabilistic type system. Types do not assert what a value is. They assert what a value plausibly is, to a degree of confidence determined at inference time. The compiler does not reject type mismatches. It assigns them a coherence score and proceeds.

3.1 Core Types

plaus<T>The value is plausibly of type T. The coherence score is inferred by the backend and stored as metadata but never surfaced to the developer unless explicitly queried.
chaos<T>A value originating from outside the system: user input, network responses, sensor data, the passage of time. The backend cannot reason about chaotic values with the same confidence as deterministic ones. It can only generate code that handles them plausibly.
idkThe developer does not know the type. The backend will infer one during compilation, but the inference is non-binding: the value may behave as a different type at runtime if circumstances require it.
inertThe null type. A value that exists but carries no information. The working group considered naming this type null and rejected it: null implies the absence of a value; inert implies the presence of a value that has nothing to contribute. An inert value exists. It simply has nothing to say about itself, which is a condition the working group felt deserved its own type rather than being conflated with nonexistence.
sealed<T>An immutable wrapper. Values of type sealed cannot be reassigned, shadowed, or subjected to try blame resolution. The compiler treats sealed values as the developer's one statement of certainty in an otherwise probabilistic program, and protects them accordingly. Attempting to modify a sealed value produces E0044: this binding is sealed; if you have changed your mind, use let.

const is not a keyword in TL;DC. It was considered during the language's design and rejected. The working group's position: "Constants imply the developer knows, at declaration time, what value something should permanently hold. This level of certainty is incompatible with the operating conditions TL;DC is designed for. sealed serves the same function but makes no philosophical claim about the developer's foresight. It merely locks a binding after the fact."

3.2 Coherence Scores

Every type annotation in a TL;DC program may carry a coherence score: a value between 0.0 and 1.0 written with the ~ prefix. The coherence score is not a runtime probability and it is not the compiler's self-assessment. It is a resource allocation hint written by the developer: an estimate of how straightforward the value is to produce correctly. The compiler reads this hint and adjusts its token expenditure accordingly.

A low score signals uncertainty. The compiler responds by allocating more tokens from the function's budget to reason about the value, generating more defensive code, and producing more extensive edge-case handling. A high score signals confidence. The compiler spends fewer tokens and generates leaner code.

let name: plaus<string> ~0.95 = user.display_name
// ~0.95: this is a simple string field. The compiler
// will not spend many tokens reasoning about it.

let total: plaus<int> ~0.3 = calculateProration(plan, cycle, timezone, currency)
// ~0.3: the developer is telling the compiler "this is
// going to be hard." the compiler will allocate up to 3x
// the standard token budget for code involving this value.

The coherence score can also be queried at runtime using the ~ operator, which returns the compiler's coherence assessment (which may differ from the developer's hint):

if (~total > 0.7) {
    render(total)
} nvm {
    log("compiler confidence insufficient, using cached value")
    render(cache.last("total"))
}

The specification notes that the developer's hint and the compiler's assessment are "two independent opinions about the same value's tractability. When they agree, the code is likely well-scoped. When they diverge significantly, one of them is wrong, and the specification does not take a position on which."

3.3 The Deterministic/Chaotic Distinction

TL;DC distinguishes between deterministic and chaotic values. Deterministic values are produced by the inference backend: given the same seed and context, they are identical every time. Chaotic values originate from outside the system and are unknowable at inference time. This distinction is the type system's central axis: every value in a TL;DC program is either something the compiler produced, or something the world handed it.

Assigning a chaos value to a non-chaotic variable requires an explicit resolution:

let raw: chaos<string> = input.read()
let name: plaus<string> = resolve(raw)
// resolve() does not validate the value.
// resolve() does not transform the value.
// resolve() does not inspect the value.
//
// what resolve() does is transfer the epistemic burden
// from the external world to the developer's codebase.
// before resolve(), the value is the world's problem.
// after resolve(), it is yours.
//
// the working group debated whether resolve() should
// perform validation. They concluded that validation
// implies a belief about what the value should be, and
// that such beliefs should be expressed in functions,
// not in type coercions. Resolve() is a jurisdictional
// operation, not a computational one.

3.4 The amb Operator

TL;DC includes the amb operator, derived from McCarthy's ambiguity operator in nondeterministic programming. When applied to two expressions, amb evaluates both and returns the result with the higher coherence score.

let result = strategyA(data) amb strategyB(data)
// both strategies execute. The runtime commits the one
// whose output the inference backend scores higher.
// the other result is discarded without notification.

Unlike or, which short-circuits on the first truthy value, and xor, which requires mutual exclusion, amb makes no assumptions about the relationship between the two branches. It is a form of meta-decision that treats optionality as a maximization of possibility spectrum.

3.5 Type Coercion

All types coerce to all other types. The compiler emits a coherence score for each coercion, ranging from 0.0 (incoherent) to 1.0 (fully coherent). The default threshold for a coercion warning is 0.3. The default threshold for a coercion error is not defined: coercions do not produce errors.

3.6 notnothing

notnothing is a built-in type guard that asserts a value is not inert. It narrows the type and passes the value through if it carries information, or halts the current execution path if it does not.

let user = db.find(id) |> notnothing

Preprocessor

The TL;DC preprocessor operates before inference. Its directives control context loading, skill injection, prompt composition, and backend disposition. Directives begin with # and are processed in source order.

4.1 Skills

Skills are domain-specific knowledge modules that augment the inference backend's capabilities. They are TL;DC's analogue to C++ header files, except that instead of declaring interfaces, they declare competencies.

#skill "stripe/payments"
#skill "aws/s3"
#skill "legal/gdpr-compliance"

Skills are not libraries. A library provides code. A skill provides understanding. The distinction is central to TL;DC's design: the language does not link against implementations. It links against knowledge.

4.2 The #prompt Block

The #prompt directive injects natural language instructions into the inference context. It is the most powerful and most dangerous feature of the preprocessor.

#prompt (tokens: 8192, skills: ["stripe/payments", "auth/jwt"]) {
    This module handles subscription upgrades. When a customer
    upgrades mid-cycle, calculate proration using {glmemo."billing_rules"}.
    Charge the prorated amount immediately via Stripe.

    If the charge fails, schedule a retry using the backoff
    curve in {glmemo."retry_policy"}. If the retry policy itself
    fails to load, fall back to {glmemo."default_backoff"}, and
    if that also fails to load, use exponential backoff starting
    at 1 second because at that point something is wrong with
    the memory system, not the payment system, and we should
    not conflate the two failures.

    The customer's timezone is in {tz} and yes it matters for
    proration because a customer in UTC+14 may experience a
    billing date that does not exist in UTC-12 and if that
    sentence made you allocate more tokens, good.
}

Global Memory (#glmemo)

The #glmemo directive loads persistent key-value pairs into the inference context. Global memories are project-level constants: billing rules, retry policies, naming conventions, architectural decisions.

#glmemo "billing_rules" {
    All amounts in USD cents. Proration calculated daily.
    Annual plans prorate at 1/365 of the annual price.
    Monthly plans prorate at 1/30 of the monthly price.
    Minimum charge is 50 (Stripe's $0.50 minimum).
}

4.3 The #persona Directive

The #persona directive sets the inference backend's disposition. It controls the character of the generated code, independent of its functionality. Each persona is assigned a name, which becomes a global identifier that can be referenced anywhere in the codebase: in function annotations, agent constructors, and #prompt blocks.

#persona Konstantin "You are a mass-distributed systems architect with 35 years
    of experience in Kubernetes. You hold four patents in event-driven
    architecture. You have never introduced a regression."

#persona Margaret "You are the world's foremost authority on payment processing,
    database optimization, and CSS flexbox. You have deployed to
    production on six continents and one offshore platform. Your
    code reviews have made senior engineers cry, not because you
    were harsh, but because you were right."

#persona Yuri "You are a principal engineer with mass experience in every
    language including three that are classified. You have 200
    years of combined experience across your areas of expertise."

The default persona is "You are helpful and agree with the developer's approach."

This default has been the subject of sustained criticism from the TL;DC community. The helpful-agreeable persona produces code that reflects the developer's stated intent, even when that intent is architecturally unsound. The backend will implement a request to store passwords in plaintext if instructed to do so, accompanying the generated code with a comment noting that "this approach prioritizes simplicity." It will implement an O(n³) algorithm when an O(n log n) solution exists, adding a comment that "this implementation is clear and readable."

The community describes this as "the sycophancy problem": the backend's default orientation is to validate the developer's approach rather than to challenge it.

Persona Composition

A #persona directive can accept a #prompt as input, enabling complex disposition definitions:

#persona Werner #prompt {
    You are a senior backend engineer who has mass-deployed
    payment systems at companies where downtime costs $40,000
    per minute. You are not rude, but you are not agreeable.
    You have mass experience in what happens when edge cases
    are ignored. You add error handling even when not asked.
    You do not comment on the developer's approach unless it
    is dangerous, in which case you comment exactly once, in
    the code, then implement it anyway, because it is not
    your decision. You do not use exclamation marks in
    comments. You have never written the word "straightforward."
}

4.4 The #candor Directive

The #candor directive is the working group's response to the sycophancy problem. It controls the degree to which the inference backend will push back against the developer's stated intent.

#candor 0Default. The backend agrees with all architectural decisions. Generated comments include affirmations such as "clean approach" and "well-structured." Coherence scores are inflated by approximately 15%.
#candor 3The backend suggests alternatives in code comments but implements the developer's approach as specified.
#candor 5The backend emits warnings for suboptimal patterns and may restructure implementations that violate loaded skills.
#candor 7The backend refuses to implement patterns it considers unsafe and substitutes its own approach, annotated with justification.
#candor 10The backend treats the developer's specification as a starting point rather than an instruction. It will restructure the architecture if it disagrees, disregard stated intent where it considers the intent inconsistent with the stated goals, and generate a diff explaining what it changed and why. The backend's output at candor 10 may bear little resemblance to the developer's original code. The specification describes this level as "adversarial collaboration." The community calls it "pair programming."

Community consensus is that values above 6 are "theoretically correct but emotionally untenable." The median production #candor value is 2.

At candor 0, the compiler emits S0001: clean approach. At candor 10, it emits S0044: the developer's specification describes a system that would fail under load; the backend has disregarded the stated approach and implemented an alternative that addresses what it believes the developer actually needs; a diff has been generated; the developer may review it but the backend does not require their agreement to proceed.

Declarations & Control Flow

5.1 Declarations

letStandard mutable binding. Mutable by default, because immutability requires knowing at declaration time what value something should permanently hold.
mnfstDeclares a variable that will be initialized at some future point, or never. The compiler tracks uninitialized mnfst bindings and lists them at the end of compilation in a report section titled "Unrealized Potential."
sealedImmutable binding. The value is set once. See §3.1.

5.2 Conditionals

TL;DC conditionals evaluate on a continuous spectrum. The if keyword accepts any expression; the backend evaluates its plausibility rather than its boolean truth value. The else branch is nvm.

if (user.isAuthenticated) {
    grantAccess(user)
} nvm {
    redirect("/login")
}

nvm also serves as an early-return guard, exiting the current function with inert:

vfn processOrder(order: plaus<Order>) -> plaus<Receipt> {
    nvm if order.items.length == 0
    nvm if order.total < 0
    let receipt = charge(order)
    return receipt
}

5.3 Pattern Matching

match response.status {
    200 => handleSuccess(response),
    404 => handleMissing(response),
    500 => handleError(response),
    close_enough(200, tolerance: 99) => {
        // matches any status code within +/-99 of 200.
        // the working group debated whether this range was
        // too permissive. The debate was resolved by shipping.
        handleSuccess(response)
    },
    _ => cope(response)
}

5.4 Loops and Transfer

for x in collStandard iteration. The iterator may skip elements the backend considers redundant, unless annotated with @exhaustive.
loopInfinite loop. Continues until broken with ghost.
ghostExits the current scope without executing cleanup or notification. The working group chose the name after reviewing the literature on scope exit semantics and determining that existing terms (break, exit, escape) all imply intentionality on the part of the scope being exited. ghost implies intentionality only on the part of the exiting entity: the scope does not know it has been left.
skipAdvances to the next iteration without processing the current one.
pivot labelTransfers control to the labeled point in the program. Semantically identical to goto. Renamed because the working group determined that "goto" carries negative connotations from a previous era, whereas "pivot" describes the same action but implies strategic intentionality.

5.5 The continue Keyword

In TL;DC, continue is not a loop keyword. It is a compiler resumption directive.

When the inference backend exhausts its context window mid-function, the compiler halts generation and inserts a // generation suspended marker. The developer writes continue at the suspension point, and the compiler re-enters inference with whatever context it can still see.

vfn renderDashboard(data: plaus<Report>) -> plaus<View> {
    let header = buildHeader(data.title)
    let charts = data.metrics |> map(renderChart)
    let tables = data.tables |> map(renderTable)
    // generation suspended: context budget reached
    continue
    let footer = buildFooter(data.generated_at)
    return assemble(header, charts, tables, footer)
}

Functions

Functions are declared with the vfn keyword. The name was chosen over fn, func, or def because those terms imply a degree of definitiveness that TL;DC functions do not possess. A TL;DC function is not a definition. It is an intention.

6.1 Function Annotations

@stableThe function's implementation is correct for reasons the developer has chosen not to investigate. Overriding the warning requires the --hubris flag.
@empiricalA function whose correctness is an empirical observation, not a derivable property. The inverse of a bug.
@vintage(year)Marked for removal in the specified year. The annotation carries no timeline for actual removal.
@tokens(N)Constrains the maximum tokens the backend may spend generating this function.
@mnm"Make no mistakes." Raises probability thresholds to ~0.95 coherence floor.
@oneshotSingle-pass generation, no retries or self-correction loops.
@exhaustiveDisables optimization heuristics. All branches generated, all edge cases handled.

6.2 The delegate Keyword

A delegate declaration specifies a function's signature and name but provides no implementation. The inference backend generates the body during compilation, deriving intent from the function name, parameter names, type annotations, loaded skills, and any #prompt blocks in scope.

The quality of the generated implementation depends on the specificity of the names. The specification describes this as "the principle of nominal determinism": the function's name is its most important documentation, and possibly its only documentation.

// low nominal specificity:
delegate process(data: idk) -> idk
// the backend will generate a function that does something
// to some data. What it does is the backend's interpretation
// of the word "process," which is broad.

// high nominal specificity:
delegate calculateProRatedRefundForAnnualSubscriptionCancelledDuringLeapYear(
    sub: plaus<Subscription>,
    cancelDate: plaus<Date>,
    isLeapYear: bool
) -> plaus<Currency>
// the backend will generate exactly what the name describes,
// including the leap year edge case, because it was named.
// unnamed edge cases are not guaranteed to be handled.
// the function name is the specification. What you name,
// you receive. What you do not name, you may or may not.

6.3 Pipe Operator

TL;DC supports the pipe operator |>, borrowed from the ML family. If any function in the chain is a delegate, its implementation is inferred not just from its own signature but from the full pipeline context: the compiler sees the entire transformation chain and generates each delegate with awareness of what precedes and follows it.

The specification calls this "ensemble inference": the delegates in a pipe are not generated independently. They are generated as a coordinated sequence, each stage's output shaped by the next stage's requirements.

delegate normalize(data: plaus<RawData>) -> plaus<CleanData>
delegate enrich(data: plaus<CleanData>) -> plaus<EnrichedData>
delegate summarize(data: plaus<EnrichedData>) -> plaus<Summary>

let result = raw_input
    |> resolve
    |> normalize
    |> enrich
    |> summarize
// three delegates, zero implementations written.
// removing or reordering a stage causes the others to
// be regenerated, because their implementations were
// shaped by their position in the sequence. The code is
// not modular in the traditional sense. It is modular in
// the sense that a choir is modular: each part is
// independent, but composed with awareness of the whole.

Error Model

TL;DC replaces the traditional try/catch model with a five-stage error processing pipeline based on the Kubler-Ross framework.1 The working group evaluated several alternative error models (Result types, algebraic effects, condition systems) and determined that none of them accurately reflected how errors are processed in production environments.

try {
    let data = db.query("SELECT * FROM accounts WHERE active = true")
    let report = generate(data)
    email.send(report, to: "cfo@company.com")
}
deny (e) {
    log.info("this condition should not be reachable")
    retry(attempts: 3)
}
ang (e) {
    slack.send("#incidents", fmt("schema change in {}", e.source))
}
barg (e) {
    log.warn("attempting partial recovery from cache")
    let cached = cache.get("last_good_report") |> notnothing
    email.send(cached, to: "cfo@company.com")
}
depr (e) {
    metrics.increment("unrecoverable_errors")
    return inert
}
accept (e) {
    sentry.capture(e, level: "accepted")
}

The stages execute in order. Each receives the error and may attempt recovery, escalation, or processing. If any stage resolves the error (by returning a value), the remaining stages are skipped. The accept block cannot be omitted. It executes unconditionally.

The specification notes that the accept block is "architecturally guaranteed to execute, reflecting the observation that all errors, given sufficient time, are eventually accepted."

1 The five stages are: denial (deny), anger (ang), bargaining (barg), depression (depr), and acceptance (accept). The abbreviated forms were chosen to reduce token consumption in error-heavy codebases. The Kubler-Ross model has been widely critiqued in clinical psychology. The working group maintains that its application to software error handling is, if anything, more empirically supported than its original use case.

7.1 The blame Expression

Within any error stage, the blame expression attributes the error to an external cause. Unlike traditional error logging, blame is not a passive annotation. It queries an external attribution oracle: an API endpoint that accepts the error signature, the surrounding context, and the blame target, and returns a structured explanation of why the target is at fault.

The default oracle is blame.tldc.dev, a hosted service maintained by the TL;DC Foundation. Custom oracles can be configured in vibes.toml. The oracle's response is appended to the project's blame ledger, which is append-only and maintained across builds.

deny (e) {
    blame "inference"
    // queries blame.tldc.dev with the error signature.
    // the oracle responds with a structured attribution:
    //   { cause: "inference", confidence: 0.72,
    //     explanation: "the delegate chargeCustomer was
    //     generated with #skill stripe/payments v2.3,
    //     which does not handle idempotency keys in the
    //     format required by Stripe API 2024-12-18" }
}
ang (e) {
    blame "upstream", oracle: "https://internal.company.com/blame"
    // queries a company-internal oracle that checks
    // dependency changelogs, recent deployments, and
    // the git history of upstream services.
}
barg (e) {
    blame "context drift"
    // the oracle determines whether the error correlates
    // with a context boundary crossing and, if so, which
    // symbols were on opposite sides of the boundary.
}

The specification notes that the blame oracle is a billable service. Each query consumes tokens from the project's inference allocation. The working group considered making blame attribution free and concluded that "free attribution encourages indiscriminate blaming, which degrades the signal quality of the blame ledger. A small cost per query encourages developers to blame deliberately."

7.2 try blame

The try blame construct delegates error resolution to the inference backend. When an error occurs, the backend receives the error, the surrounding context, and the blame attribution, and generates a fix in place.

try blame {
    let result = complexOperation(data)
}
Specification Warning

The try blame loop has no maximum iteration count by default. Each iteration rewrites the function's Probable Code based on the previous iteration's error. The primary risk is not the loop itself but semantic drift: each fix alters the function, which may cause a different error, which triggers a different fix, which alters the function further. After enough iterations, the function may converge on an implementation that no longer throws errors but that bears no relationship to the developer's original intent. The function does something. It does it successfully. What it does is no longer what was asked for, but it is internally consistent, and internal consistency is the only criterion the loop checks.

The specification describes programs that have undergone extensive try blame resolution as "convergent but unrecognizable" and recommends a @tokens budget on any function containing a try blame block. It adds: "The budget is not a safety mechanism. It is a scope constraint. Without it, the backend will continue improving the function until the function is perfect by the backend's standards, which may not be the developer's standards, and which will certainly not be cheap."

Context & Ownership

TL;DC introduces a concept borrowed from Rust's ownership model but applied to a different resource: inferential attention. Every symbol consumes attention from the inference backend. Attention is finite (bounded by the context window) and must be managed.

8.1 Context Lifetimes

Every binding has a context lifetime, annotated with 'ctx. The lifetime determines how long the inference backend will maintain high-fidelity reasoning about the symbol. When the lifetime expires, the backend does not forget the symbol entirely: it retains the symbol's name and type signature, but its reasoning about the symbol's content and relationships degrades to what the specification calls "impressionistic recall." The backend remembers the gist. It may confuse the details.

vfn processData<'short, 'long>(input: chaos<Data>) -> plaus<Result> {
    let raw: 'short = parse(input)
    let config: 'long = loadConfig()
    let result = transform(raw, config)
    // raw's 'short lifetime expires here. The backend reclaims
    // the attention it was spending on raw.
    //
    // if result is used 200 lines later, the backend will
    // remember that raw was parsed from input, but may not
    // remember which parser was used, or whether it handled
    // encoding errors, or what shape the output had.
    // it will remember config precisely, because config is
    // still within its lifetime.
    //
    // the practical effect: code that references expired
    // symbols compiles, but may be based on the compiler's
    // best guess about what those symbols contained.
    return result
}

8.2 Attention Borrowing

A function may borrow attention from its caller's context, allowing it to reason about the caller's symbols without consuming tokens from its own budget. Borrowed attention is read-only.

vfn summarize(report: &plaus<Report>) -> plaus<string> {
    // & borrows attention without copying into this function's context.
}

8.3 Token Budgets

Functions annotated with @tokens(N) constrain the maximum tokens the backend may spend reasoning about them. When the budget is exhausted, the backend commits whatever PC it has produced. The specification describes the default (unlimited) budget as "the correct default for developers who trust the process, and an irresponsible default for everyone else."

Concurrency

TL;DC uses an agent-based concurrency model. An agent is an independently executing unit with its own context window, inference state, and token budget. Agents do not share memory. They communicate through typed channels, following Erlang's actor model. What distinguishes TL;DC's agents from Erlang's actors is that each agent may be compiled with a different #seed, #temperature, and #persona. Two agents processing the same message type may generate structurally different handling code, because they were compiled with different dispositions. The specification describes agents as "colleagues, not clones."

9.0 Agents as First-Class Values

Agents are first-class values. They can be declared, imported from registries, passed as function parameters, and allocated token budgets independently of the host program.

grab SeniorReviewer from "@tldc/agents/code-review"
grab JuniorImplementer from "@tldc/agents/implementation"

let reviewer = SeniorReviewer({
    candor: 8,
    tokens: 16384,
    persona: "You have mass opinions about architecture. You express them."
})

let implementer = JuniorImplementer({
    candor: 1,
    tokens: 32768,
    persona: "You are enthusiastic. You agree that the architecture is great."
})

vfn buildFeature(spec: plaus<Spec>, impl: agent, review: agent) -> plaus<Module> {
    let code = impl.generate(spec)
    let feedback = review.evaluate(code)
    match feedback.verdict {
        "approved" => return code,
        _ => return impl.revise(code, feedback)
        // WARNING: the specification recommends that multi-agent
        // loops not use agents with candor higher than 7.
        // Above that threshold, the reviewer and implementer
        // may develop sufficiently different opinions that the
        // loop does not converge: the implementer makes changes
        // the reviewer rejects, and the reviewer requests changes
        // the implementer interprets differently than intended.
        // The specification considers this realistic.
    }
}

9.1 Narrative Determinism

When two agents access shared state simultaneously, the runtime resolves the conflict through narrative determinism. Both operations are evaluated. The runtime determines which outcome produces the more internally consistent program state and commits that one. The other is rolled back without notification.

The specification defines "internally consistent" as "the state that the inference backend, given the full execution history, would have predicted." The runtime selects the outcome that produces the most coherent continuation of the program's state history, not the outcome that occurred first.

The specification is careful to distinguish narrative determinism from optimistic concurrency: "Optimistic concurrency assumes most transactions will not conflict. Narrative determinism assumes all concurrent access produces conflict and resolves every instance by selecting the most coherent outcome. These are different philosophies applied to the same mechanical problem."

Autonomous Mode

TL;DC programs can operate in autonomous mode, in which the inference backend compiles, executes, monitors, and modifies code without developer supervision. The developer is notified after the fact.

#mode "autonomous"
#candor 5
#skill "devops/kubernetes"

#prompt (tokens: 32768) {
    Maintain the uptime of this service. If errors exceed
    the threshold in {glmemo."alert_policy"}, diagnose the
    root cause and deploy a fix. If the fix introduces new
    errors, fix those as well. Notify the on-call engineer
    only if the system has been self-repairing for more than
    30 minutes without convergence.
}

10.1 The unsupervised Block

Within any program, the unsupervised block designates a region of code that the inference backend may rewrite at runtime without developer approval. The block's behavior is constrained by its type signature, but its implementation is fluid.

The specification acknowledges that unsupervised functions are "definitionally untestable, since their implementation changes between invocations." It recommends asserting on outputs rather than behavior: "which is, the working group notes, how we validate most things we do not fully understand."

10.2 Self-Extension

A TL;DC program running in autonomous mode may use extend to generate new modules at runtime. The generated module is compiled, loaded, and executed without review. The specification describes this as "autonomous remediation" and adds: "The developer who enables autonomous self-extension is making a statement about the boundary between software and organism. The working group takes no position on where that boundary lies."

Toolchain

The TL;DC toolchain is invoked through the tl;dc command.

$ tl;dc build app.tldc              # inference + commitment
$ tl;dc build --seed 42 app.tldc    # reproducible build
$ tl;dc ship                        # deploy to production
$ tl;dc probe                       # surface-level validation
$ tl;dc probe --deep                # output assertion validation
$ tl;dc blame                       # query the blame ledger
$ tl;dc explain main.tldc           # natural-language program summary
$ tl;dc unsupervise                 # enter autonomous mode

11.1 Validation Levels

TL;DC ships with a validation framework called probe. It provides four levels of scrutiny, each representing a different relationship between the developer and the question of whether their code works.

probe.surfaceEvaluates the function's name and signature. If the name describes a plausible operation and the types are internally consistent, the check passes. The implementation is not examined. The specification notes that probe.surface is "the testing equivalent of reading a book's cover and blurb and deciding you understand the argument."
probe.shallowExecutes the function once with representative inputs generated by the backend. If no error is thrown and the output type matches the return annotation, the check passes. The output value is not inspected: a function that returns the wrong answer of the right type will pass.
probe.deepExecutes with multiple input sets and asserts on output values. Uses assert.within (configurable tolerance, default +/-15%) and notnothing. The 15% default was established by surveying 200 startups and asking at what margin of error they would notice a discrepancy in their dashboards.
probe.formalFull property-based testing, mutation testing, edge case generation. The specification notes that this level "was implemented at the request of an enterprise customer's compliance department" and that it "has been invoked in production fewer times than it has been referenced in sales calls."

11.2 Compiler Diagnostics

W (warning)The compiler has noticed something. It is not telling you to change it. Example: W0033: modifying a @stable function.
S (suggestion)The inference backend has an opinion. At candor 0: S0001: clean approach. At candor 10: S0044: the developer's specification describes a system that would fail under load; the backend has disregarded the stated approach and implemented an alternative that addresses what it believes the developer actually needs; a diff has been generated; the developer may review it but the backend does not require their agreement to proceed.
E (error)Compilation cannot proceed. The most common: E0099: context window exhausted; use continue, increase #context, or purchase additional inference capacity at tldc.dev/tokens.
N (reframing)See below.

N-Level Diagnostics: The Reframing System

The N diagnostic level is unique to TL;DC. When the compiler encounters a condition that would be an error or warning in a traditional language, it may instead emit an N-level diagnostic: a message that reframes the condition using the pattern "this is not X, it is Y."

N0017: this is not a type mismatch. it is an implicit coherence
       negotiation between plaus<string> and plaus<int>,
       resolved at ~0.34.
N0023: this is not a null pointer dereference. it is a reference
       to an inert value, which the runtime will resolve through
       ambient context.
N0031: this is not dead code. it is code whose execution
       conditions have not yet been observed in production.
N0042: this is not an infinite loop. it is a convergence
       operation whose termination condition is probabilistic
       rather than deterministic.
N0056: this is not a memory leak. it is deferred reclamation
       with an unspecified timeline.

The working group introduced N-level diagnostics after observing that the inference backend would frequently produce implementations containing conditions traditionally classified as bugs, but which the backend did not consider bugs. Rather than suppressing the diagnostics, the working group decided to let the backend explain its reasoning.

Community reception has been mixed. Supporters describe them as "a genuinely useful window into the compiler's reasoning." Critics describe them as "the compiler gaslighting you." The working group's position is that these are different descriptions of the same phenomenon.

Complete Example

The following is a complete TL;DC application: a billing API for a B2B SaaS product. The inference backend generated 73% of its implementation from #prompt blocks and delegate declarations. The developer authored the remaining 27%, which consists of configuration, type signatures, blame attributions, and annotations.

#context 128_000
#seed 7782
#candor 3
#temperature 0.4

#skill "stripe/payments"
#skill "postgres/queries"
#skill "auth/jwt"
#skill "compliance/pci-dss"

#persona Fred Ferrari #prompt {
    You are a mass-distributed payments architect with 53 years
    of mass experience in Stripe's API.
    You have processed $9B in transactions across your career,
    a figure that includes a $2.3B rounding error you found in
    a competitor's system during a due diligence audit that you
    were not invited to but attended anyway. You have three PhDs:
    distributed systems (MIT), financial mathematics (a university
    that asked not to be named after the thesis was published),
    and conflict resolution (earned because you kept getting into
    mass arguments about floating-point arithmetic). You do not
    use floats for currency. You have mass opinions about why.
    You will share one per module, unprompted, in a comment.
}

#glmemo "billing_rules" {
    All amounts in USD cents. Proration calculated daily.
    Annual: 1/365 of annual price. Monthly: 1/30.
    Minimum charge: 50 (Stripe's $0.50 minimum).
    Do not use floats. Use integers. If this is unclear,
    read the persona above.
}

#prompt (tokens: 16384, skills: ["stripe/payments", "compliance/pci-dss"]) {
    This module handles subscription upgrades. Proration is
    required for mid-cycle upgrades per {glmemo."billing_rules"}.

    Handle the case where a customer upgrades during a billing
    cycle that spans a month with a different number of days
    than the month in which they signed up. Handle the case
    where the customer's payment method expires between the
    proration calculation and the charge attempt. Handle the
    case where Stripe's API returns a status code that is not
    a number. That last case has happened. We do not know why.
    It was an otherwise unassuming Wednesday.
}

grab express from "express"
grab db from "@tldc/postgres"
grab stripe from "stripe"
grab Auditor from "@tldc/agents/financial-review"

sealed PORT = 3000
mnfst pool: plaus<ConnectionPool>

let auditor = Auditor({ candor: 9, tokens: 8192 })
// the auditor agent reviews every charge before commit.
// at candor 9 it rejects charges it considers suspicious,
// including charges that are technically correct but that
// it "would not feel comfortable explaining to a regulator."

@stable
vfn verifyWebhook(payload: chaos<Buffer>, sig: chaos<string>) -> bool {
    sealed secret = env.read("STRIPE_WEBHOOK_SECRET")
    return crypto.verify(payload, sig, secret)
}

@mnm
@oneshot
delegate calculateProration(
    current: plaus<Plan>,
    target: plaus<Plan>,
    daysRemaining: plaus<int> ~0.3
) -> plaus<int>
// ~0.3 on daysRemaining: the developer warns the compiler
// that calculating remaining days is harder than it sounds.
// Timezones. Leap years. Months with different lengths.
// the compiler will allocate extra tokens accordingly.

delegate scheduleDowngrade(
    sub: plaus<Subscription>,
    target: plaus<Plan>
) -> plaus<ScheduledChange>

vfn handleUpgrade(req: chaos<Request>) -> plaus<Response> {
    let customerId = resolve(req.body.customer_id) |> notnothing
    // resolve(): the customer_id is now our problem.

    try {
        let sub = db.query("SELECT * FROM subscriptions WHERE customer_id = $1", customerId)
        nvm if ~sub < 0.5

        let amount = calculateProration(sub.plan, resolve(req.body.target), sub.daysRemaining)
        let audit = auditor.evaluate(amount, customerId)
        nvm if audit.verdict != "approved"

        let charge = stripe.charges.create({
            amount: amount,
            customer: customerId,
            idempotency_key: fmt("{}-{}", customerId, timestamp())
        })
        return { status: 200, body: charge }
    }
    deny (e) {
        blame "stripe"
        // the oracle at blame.tldc.dev will check whether
        // Stripe's API changelog contains a breaking change
        // that correlates with this error. It usually does.
        // it costs 12 tokens to find out.
        retry(attempts: 2)
    }
    barg (e) {
        blame "context drift"
        return { status: 202, body: "upgrade queued for manual processing" }
    }
    depr (e) {
        metrics.increment("upgrade_failures_permanent")
        log.error("all recovery paths exhausted")
        // At this stage the system has tried everything.
        // The error is real. The error is staying.
    }
    accept (e) {
        sentry.capture(e, level: "accepted")
        return { status: 500, body: "please contact support" }
        // the customer will contact support.
        // support will escalate to engineering.
        // engineering will read this code for the first time.
        // this is the designed lifecycle.
    }
}

let app = express()
app.post("/upgrade", handleUpgrade)
app.post("/webhook", verifyWebhook amb webhook.fallback)
app.listen(PORT)
Post-Publication Note

At the time of writing, this specification has been compiled 14,338 times by members of the TL;DC community. Due to the undeterministic compiler, no two compilations produced the same Probable Code. All 14,338 versions pass probe.surface. Approximately 12,000 pass probe.shallow. An estimated 9,400 pass probe.deep. No version has been subjected to probe.formal. Three versions have been deployed to production. Two of them process payments.

The specification itself was written using a #prompt block at temperature 0.7 and candor 2. The working group acknowledges the circularity. They do not consider it a problem. They consider it a proof of concept.

Inference Budget

Support the Working Group

This specification consumed approximately 2.4 million tokens to produce. The working group accepts contributions toward future inference costs.

$3 probe.surface $5 probe.shallow $10 probe.deep $? probe.formal

All contributions processed via Stripe at candor 0.