Skip to content

Rune and AI โ€‹

Inference vs Declaration โ€‹

When AI works with a codebase it has two modes: infer or read.

Inference is archaeology โ€” reconstructing intent from artifacts. AI reads property names, guesses mutability from setter presence, searches scattered comments for rationale, probabilistically determines which methods are user-facing. The quality of that reconstruction degrades with codebase size, naming inconsistency, and comment staleness. It is always approximate.

Declaration is direct. The system states what it is. AI reads it.

Rune is a declaration protocol. Every binding announces its nature โ€” mutable or derived, display or input, action or annotation โ€” structurally, in the type system, co-located with the code it describes. AI doesn't reconstruct the system's intent. It reads the system's own description of itself.


C# โ€” Inference vs Declaration โ€‹

Mutable state (~) โ€‹

Without Rune โ€” AI infers:

csharp
// AI works backwards:
// setter exists โ†’ probably mutable
// name suggests a threshold โ†’ probably user-configurable
// no comment โ†’ rationale unknown
// nothing prevents direct assignment from anywhere in the codebase
public decimal RiskThreshold { get; set; } = 0.15m;

With Rune โ€” AI reads:

csharp
// AI reads this directly โ€” nothing to infer:
// [RuneState]  โ†’ mutable, sync target, two-way binding
// [RuneIntent] โ†’ rationale is structural, not guessed
// only registered [RuneAction] methods can change this through the host
[RuneState]
[RuneIntent("approved by risk committee Q1-2025 โ€” review at quarter end")]
public decimal RiskThreshold { get; set; } = 0.15m;

Computed / read-only (@) โ€‹

Without Rune โ€” AI infers:

csharp
// AI infers:
// getter-only โ†’ probably derived
// filters Tasks โ†’ but can a subclass override it? can it be wrong?
// nothing structurally prevents a ~ sync binding targeting this
public IEnumerable<TaskItem> Pending => Tasks.Where(t => !t.Done);

With Rune โ€” AI reads:

csharp
// AI reads:
// [RuneComputed] โ†’ derived, read-only, structurally cannot be a sync target
// attempting host.Sync("pending", ...) throws RNE003 โ€” not a convention, a guarantee
[RuneComputed]
public IEnumerable<TaskItem> Pending => Tasks.Where(t => !t.Done);

Action (!) โ€‹

Without Rune โ€” AI infers:

csharp
// AI infers:
// public method โ†’ might be user-triggered, might be internal utility
// name suggests submission โ†’ probably consequential
// no way to know if it's audited, logged, or reversible
// no way to know if this is the only path to submission
public async Task SubmitOrder(Guid orderId) { ... }

With Rune โ€” AI reads:

csharp
// AI reads:
// [RuneAction] โ†’ explicitly user-triggered, registered in the action surface
// [RuneIntent] โ†’ consequences are declared, not inferred
// host.Actions is the complete list โ€” no undeclared entry points exist
[RuneAction("submit-order")]
[RuneIntent("explicit, logged to OMS, irrevocable โ€” pre-trade risk check runs here")]
public async Task SubmitOrder(Guid orderId) { ... }

Intent (?) โ€‹

Without Rune โ€” AI infers:

csharp
// AI searches:
// comments? โ†’ "// default 100" โ€” tells AI nothing about why
// PR history? โ†’ might not be in context
// Confluence? โ†’ not in the codebase
// the person who set this? โ†’ probably left
public int MaxConnections { get; set; } = 100;

With Rune โ€” AI reads:

csharp
// AI reads the rationale directly โ€” same session, every session, always current
[RuneState]
[RuneIntent("approved range 50โ€“200 per capacity plan โ€” tuned for p99 latency < 20ms")]
public int MaxConnections { get; set; } = 100;

A Complete Class โ€” Before and After โ€‹

The transformation at scale. An order entry form โ€” first as standard C# MVVM, then with Rune.

Without Rune:

csharp
public class OrderEntryViewModel : INotifyPropertyChanged
{
    public string InstrumentName  { get; private set; }
    public decimal LastPrice      { get; private set; }
    public decimal BuyingPower    { get; private set; }

    public decimal Quantity       { get; set; }
    public string  OrderType      { get; set; } = "MARKET";
    public decimal LimitPrice     { get; set; }

    public ICommand PlaceOrderCommand  { get; }
    public ICommand CancelOrderCommand { get; }

    // AI questions with no answers in the code:
    // Which properties are display-only vs user-editable?
    // What are the constraints on Quantity?
    // Why is the default order type MARKET, not LIMIT?
    // What happens when PlaceOrder executes? Is it reversible?
    // Do risk checks run on field change or on PlaceOrder?
}

With Rune:

csharp
public class OrderEntryViewModel
{
    // @ display only โ€” feed-driven, structurally non-writable
    [RuneComputed]
    public string  InstrumentName => _feed.GetName(_instrumentId);

    [RuneComputed]
    public decimal LastPrice      => _feed.GetLastPrice(_instrumentId);

    [RuneComputed]
    public decimal BuyingPower    => _account.GetBuyingPower();

    // ~ user-editable fields โ€” named, constrained, intentional
    [RuneState]
    [RuneIntent("round lot enforcement: min 100, multiples of 100")]
    public decimal Quantity  { get; set; }

    [RuneState]
    [RuneIntent("market or limit only โ€” stop orders require separate workflow")]
    public string OrderType  { get; set; } = "MARKET";

    [RuneState]
    [RuneIntent("required when order-type = limit โ€” validation runs in !place-order")]
    public decimal LimitPrice { get; set; }

    // ! explicit actions โ€” the only sanctioned mutation paths
    [RuneAction("place-order")]
    [RuneIntent("pre-trade risk checks run here โ€” not on field changes")]
    public async Task PlaceOrder() { ... }

    [RuneAction("cancel-order")]
    public async Task CancelOrder(Guid orderId) { ... }
}

What AI reads from the Rune version โ€” without inference:

  • 3 computed values (display-only, structurally non-writable)
  • 3 mutable fields (named sync targets, each with governance rationale)
  • 2 actions (complete action surface โ€” nothing else can trigger behavior)
  • Every constraint co-located with the field it governs
  • "pre-trade risk checks run here โ€” not on field changes" โ€” a governance claim in the type system

React / TypeScript โ€” Inference vs Declaration โ€‹

Mutable state (~) โ€‹

Without Rune โ€” AI infers:

tsx
// AI infers:
// useState โ†’ mutable, but what is the governance boundary?
// passed to input value + onChange โ†’ probably two-way
// name is local to this component โ€” no identity outside it
// rationale: nowhere
const [riskThreshold, setRiskThreshold] = useState(0.15);

<input
  value={riskThreshold}
  onChange={e => setRiskThreshold(parseFloat(e.target.value))}
/>

With Rune โ€” AI reads:

tsx
// AI reads:
// useSync('risk-threshold') โ†’ named sync binding, canonical cross-stack identity
// host carries intent for 'risk-threshold' โ€” rationale accessible via host.intent.for(...)
// mutation surface is the host โ€” not scattered local setters
const [riskThreshold, setRiskThreshold] = useSync<number>('risk-threshold');

<input
  value={riskThreshold}
  onChange={e => setRiskThreshold(parseFloat(e.target.value))}
/>

Read-only display (@) โ€‹

Without Rune โ€” AI infers:

tsx
// AI infers:
// no setter โ†’ probably display-only, but nothing enforces it
// could be passed a setter prop and become mutable
// derived from props or external state? unclear without tracing
<span>{marketPrice}</span>

With Rune โ€” AI reads:

tsx
// AI reads:
// useRead('market-price') โ†’ read-only binding, structurally cannot sync
// host.state.isComputed('market-price') === true โ€” feed-driven, not user-editable
const marketPrice = useRead<number>('market-price');

<span>{marketPrice}</span>

Action (!) โ€‹

Without Rune โ€” AI infers:

tsx
// AI infers:
// async function โ†’ probably consequential
// calls submitOrder โ†’ side effect somewhere downstream
// onClick handler โ†’ user-triggered, but is it the only entry point?
// no way to enumerate all actions in this screen
const handleSubmit = async () => {
  await riskService.submitOrder(orderId);
};

<button onClick={handleSubmit}>Submit Order</button>

With Rune โ€” AI reads:

tsx
// AI reads:
// useAct('submit-order') โ†’ named, registered, part of a complete action surface
// host.actions is the only path โ€” structural guarantee, not convention
// intent: "explicit, logged to OMS, irrevocable" โ€” carried by the host
const submitOrder = useAct('submit-order');

<button onClick={() => submitOrder(orderId)}>Submit Order</button>

Intent (?) โ€‹

Without Rune โ€” AI infers:

tsx
// AI searches:
// prop name 'timeInForce' โ†’ some finance term
// default 'DAY' โ†’ standard, but why not GTC?
// no comment, no constraint, no rationale
// AI approximates based on domain knowledge โ€” might be wrong
<select value={timeInForce} onChange={...}>

With Rune โ€” AI reads:

tsx
// AI reads the rationale โ€” no domain approximation needed
useIntent('time-in-force',
  'default DAY โ€” GTC requires compliance pre-approval');

<select value={timeInForce} onChange={...}>

What This Means in Practice โ€‹

Without RuneWith Rune
Is this field editable?Infer from setter, prop type, component usage[RuneState] / useSync โ€” declared
Is this value derived?Infer from getter-only, naming[RuneComputed] / useRead โ€” declared
What can a user trigger?Read all event handlers, all commandshost.Actions โ€” complete, enumerable
Why does this value exist?Search comments, PRs, wikis[RuneIntent] / useIntent โ€” co-located
Is this safe to change?Trace all usages, approximate risk@ vs ~ โ€” structural answer
What changed this state?Trace all setters, all mutationsNamed ! action โ€” one answer

The shift is not incremental improvement in AI-assisted development. It is a change in kind โ€” from a codebase that AI reads probabilistically to a codebase that speaks directly to any reader, human or machine, in a grammar that does not decay.