Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
a4aefed
B1 (b): capability-keyed sharing contract replaces RequiredTraitWitne…
Aug 19, 2026
4815aff
Name the two residues review 53861 found, with their triggers
Aug 19, 2026
624fbb1
Census note: state the sizing correction without restating counts
Aug 19, 2026
c0fc9e4
B1 PR 2 (Option A): collapse TargetDeriveTraitKey into TargetCapabili…
Aug 20, 2026
2a0e45f
Split the capability model: agnostic half stays in std, Rust rows mov…
Aug 20, 2026
4c267c2
Complete the capability-key migration: consumers rewired, and two def…
Aug 20, 2026
15b2750
Stop laundering the closed alphabet through the open key brand (revie…
Aug 20, 2026
2272f66
Floor run found a third discriminant-on-a-Symbol site: a fixture my o…
Aug 20, 2026
1304c39
Recut the bootstrap seam: std names no capability carrier, one key + …
Aug 20, 2026
1acc115
Delete the rank projection: a second identity on ReprGroundingDeriveE…
Aug 20, 2026
3a8acdf
Merge remote-tracking branch 'origin/main' into session/quick-lynx-62…
Aug 20, 2026
ae2fb03
An empty import list silently corrupts the emitted crate layout: dele…
Aug 20, 2026
3e00f09
Retract the causal claim on ae2fb03e3d: the empty import changed noth…
Aug 20, 2026
0cbc6a0
Merge origin/main into session/quick-lynx-620-pr2
Aug 20, 2026
9395926
Merge origin/main into session/quick-lynx-620-pr2
Aug 20, 2026
69ff5f4
Stop storing the capability-eligibility index in the realization record
Aug 21, 2026
568b940
Drop the eligibility Map entirely: the rows are the lookup
Aug 21, 2026
b7ed7aa
Remove the last Map from the eligibility path: duplicate detection sc…
Aug 21, 2026
7832314
Merge branch 'main' into session/quick-lynx-620
briansrls Aug 21, 2026
d6c13ed
Merge remote-tracking branch 'origin/session/quick-lynx-620' into ses…
Aug 21, 2026
4d46bef
Merge branch 'main' into session/quick-lynx-620-pr2
Aug 21, 2026
b8458ff
Merge branch 'main' into session/quick-lynx-620-pr2
Aug 21, 2026
5f7c23a
Duplicate detection was quadratic twice over: one keyed accumulator r…
Aug 21, 2026
bd92891
Merge branch 'main' into session/quick-lynx-620-pr2
Aug 21, 2026
760b38b
Install the emitted stage0 mirror for the re-homed capability alphabe…
Aug 21, 2026
c3a8598
Merge branch 'main' into session/quick-lynx-620-pr2
Aug 21, 2026
3fddce7
Re-home main's two new Ord-propagation call sites onto RustCapability…
Aug 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
351 changes: 351 additions & 0 deletions dag/extdeps/languages/rust/capabilities.dag
Original file line number Diff line number Diff line change
@@ -0,0 +1,351 @@
module extdeps.languages.rust.capabilities

import std.trait_derive_shape {
ReprGroundingDeriveElemShape,
ReprDeriveElemKernelString,
ReprDeriveElemKernelInt,
ReprDeriveElemKernelBool,
ReprDeriveElemKernelUnit,
ReprDeriveElemNullaryEnumCopy,
ReprDeriveElemSymbolWrappedOrdCarrier,
ReprDeriveElemPayloadCoproduct,
ReprDeriveElemUnknown,
TargetCapabilityShapeRow,
TargetCapabilityShapeTable
}
import std.algebra {
Cons,
Empty
}

data rust_capabilities_note: String = "Rust and serde CAPABILITY ROWS for the B1 capability-keyed model (operator ruling 2026-08-19, option b). std.trait_derive_shape holds the AGNOSTIC half -- the source-shape vocabulary and a table lookup PARAMETERIZED on the capability carrier, naming no carrier itself. THIS module holds the RUST-SPECIFIC half: the closed RustCapability alphabet, the shape-by-capability rows instantiated at K = RustCapability, and the derive-trait list builders. A new target language adds a sibling module of rows here and edits neither the fold nor std -- DESIGN section 4: a new target language is ROWS in extdeps/languages, never an edit to the fold. WHY THE COPRODUCT WAS THE WRONG CARRIER FOR THE INTERFACE: Serialize and Deserialize are serde names, not Rust language names -- an independently versioned upstream -- and their spellings were ALREADY cited in extdeps.languages.rust.emit, so the std coproduct was a redundant KEY SET forked from a key extdeps already spelled out. WHY IT IS STILL THE RIGHT CARRIER FOR THE REALIZATION: an open Symbol brand cannot be matched exhaustively, and rust_trait_derive_spelling is TOTAL by exhaustive match. So the alphabet is re-homed here rather than deleted, and because the std predicate is generic the seed path speaks the alphabet END TO END -- v1.compiler.trait_derive_emit instantiates the predicate at K = RustCapability and needs no lift into the open key space at all. An earlier revision of this migration carried rust_capability_key and rust_capability_keys to perform exactly that lift; parameterizing std deleted both, which is the usual tell that the decomposition is right. ROW FIDELITY: the rows below were extracted mechanically from the predecessor nested match and verified cell-for-cell -- 71 admitted pairs extracted against 71 in the source -- rather than re-derived by hand. WHAT IS DELIBERATELY ABSENT: sixteen one-line data rows binding each key name to its symbol literal, and a rust_capability_emission_order list, were authored in this migration and NEVER REFERENCED -- experimental residue by DESIGN section 6, deleted rather than left to read as authority. Emission order is carried by the list builders, which is where it was before this migration."

fn rust_capability_shape_table() -> TargetCapabilityShapeTable<RustCapability> {
TargetCapabilityShapeTable {
rows: [
TargetCapabilityShapeRow {
shape: ReprDeriveElemKernelString,
capabilities: [
RustDebug,
RustClone,
RustPartialEq,
RustEq,
RustPartialOrd,
RustOrd,
RustHash,
RustSerialize,
RustDeserialize
]
},
TargetCapabilityShapeRow {
shape: ReprDeriveElemKernelInt,
capabilities: [
RustDebug,
RustClone,
RustCopy,
RustPartialEq,
RustEq,
RustPartialOrd,
RustOrd,
RustHash,
RustSerialize,
RustDeserialize,
RustAdd,
RustSub,
RustMul,
RustDiv,
RustRem,
RustNeg
]
},
TargetCapabilityShapeRow {
shape: ReprDeriveElemKernelBool,
capabilities: [
RustDebug,
RustClone,
RustCopy,
RustPartialEq,
RustEq,
RustPartialOrd,
RustOrd,
RustHash,
RustSerialize,
RustDeserialize
]
},
TargetCapabilityShapeRow {
shape: ReprDeriveElemKernelUnit,
capabilities: [
RustDebug,
RustClone,
RustCopy,
RustPartialEq,
RustEq,
RustPartialOrd,
RustOrd,
RustHash,
RustSerialize,
RustDeserialize
]
},
TargetCapabilityShapeRow {
shape: ReprDeriveElemNullaryEnumCopy,
capabilities: [
RustDebug,
RustClone,
RustCopy,
RustPartialEq,
RustEq,
RustPartialOrd,
RustOrd,
RustHash,
RustSerialize,
RustDeserialize
]
},
TargetCapabilityShapeRow {
shape: ReprDeriveElemSymbolWrappedOrdCarrier,
capabilities: [
RustDebug,
RustClone,
RustPartialEq,
RustEq,
RustPartialOrd,
RustOrd,
RustHash,
RustSerialize,
RustDeserialize
]
},
TargetCapabilityShapeRow {
shape: ReprDeriveElemPayloadCoproduct,
capabilities: [
RustDebug,
RustClone,
RustPartialEq,
RustEq,
RustHash,
RustSerialize,
RustDeserialize
]
},
TargetCapabilityShapeRow {
shape: ReprDeriveElemUnknown,
capabilities: []
}
]
}
}

type RustCapability
= RustDebug
| RustClone
| RustCopy
| RustPartialEq
| RustEq
| RustPartialOrd
| RustOrd
| RustHash
| RustSerialize
| RustDeserialize
| RustAdd
| RustSub
| RustMul
| RustDiv
| RustRem
| RustNeg

data rust_capability_alphabet_note: String = "CLOSED Rust capability alphabet. The B1 keyed contract makes TargetCapabilityKey an OPEN Symbol brand so unrelated modules can share one key space without a coproduct edit -- but an open brand cannot be matched exhaustively, and rust_trait_derive_spelling was TOTAL by exhaustive match before this migration. Deleting the coproduct outright would have traded a structural guarantee (DESIGN section 4b: no Accepted program can spell an unknown capability) for a runtime refusal, which is a rung DROP dressed as a migration. So the coproduct is RE-HOMED rather than deleted: this closed alphabet is Rust s own realization vocabulary, exhaustive at every spelling site, and rust_capability_key is the single total producer that lifts it into the shared open key space. Interface speaks keys; realization speaks the alphabet (DESIGN section 3)."


fn record_derive_traits_heap() -> List<RustCapability> {
Cons {
head: RustDebug,
tail: Cons {
head: RustClone,
tail: Cons {
head: RustPartialEq,
tail: Cons {
head: RustSerialize,
tail: Cons { head: RustDeserialize, tail: Empty }
}
}
}
}
}

fn record_derive_traits_copy() -> List<RustCapability> {
Cons {
head: RustDebug,
tail: Cons {
head: RustClone,
tail: Cons {
head: RustCopy,
tail: Cons {
head: RustPartialEq,
tail: Cons {
head: RustSerialize,
tail: Cons { head: RustDeserialize, tail: Empty }
}
}
}
}
}
}

fn nullary_coproduct_derive_traits() -> List<RustCapability> {
Cons {
head: RustDebug,
tail: Cons {
head: RustClone,
tail: Cons {
head: RustCopy,
tail: Cons {
head: RustPartialEq,
tail: Cons {
head: RustEq,
tail: Cons {
head: RustPartialOrd,
tail: Cons {
head: RustOrd,
tail: Cons {
head: RustSerialize,
tail: Cons { head: RustDeserialize, tail: Empty }
}
}
}
}
}
}
}
}
}

fn symbol_wrapped_ord_carrier_derive_traits() -> List<RustCapability> {
Cons {
head: RustDebug,
tail: Cons {
head: RustClone,
tail: Cons {
head: RustPartialEq,
tail: Cons {
head: RustEq,
tail: Cons {
head: RustPartialOrd,
tail: Cons {
head: RustOrd,
tail: Cons {
head: RustSerialize,
tail: Cons { head: RustDeserialize, tail: Empty }
}
}
}
}
}
}
}
}

fn fn_field_derive_traits() -> List<RustCapability> {
Cons { head: RustClone, tail: Empty }
}

fn payload_coproduct_derive_traits() -> List<RustCapability> {
Cons {
head: RustDebug,
tail: Cons {
head: RustClone,
tail: Cons {
head: RustPartialEq,
tail: Cons {
head: RustSerialize,
tail: Cons { head: RustDeserialize, tail: Empty }
}
}
}
}
}

// USAGE-DERIVED half of the roster, distinct from the SHAPE-derived rosters above and additive to
// them. The rosters above answer what a type's own structure can support; they cannot answer what a
// type's USE demands, so a record reaching a keyed-collection key position carries a requirement no
// shape classification produces. map_key_required_derive_traits names that requirement once: a keyed
// collection realized as a hash map bounds its key parameter by Hash + Eq (im 15.1.0 HashMap<K, V>
// declares K: Hash + Eq, matching std::collections::HashMap), so the key type must derive both. The
// requirement is target-agnostic here and spelled per target in extdeps.languages.rust.emit. Union is
// append-only and idempotent (derive_traits_union), so a type that already earns a trait from its
// shape roster gains nothing and its emitted bytes do not move — the asymmetry a fixed wider roster
// cannot express: a Symbol-wrapped ord carrier already derives Eq and needs only Hash, while a plain
// record needs both. NOT the same axis as the Ord requirement BTreeSet elements carry
// (rust_btree_set_element_ord_eligible), which is answered today by refusing at the use site rather
// than by propagating to the declaration; unifying the two on this fn is the named next step and
// deliberately not taken here.
fn phantom_opaque_carrier_derive_traits() -> List<RustCapability> {
Cons {
head: RustDebug,
tail: Cons {
head: RustClone,
tail: Cons {
head: RustCopy,
tail: Cons {
head: RustPartialEq,
tail: Cons {
head: RustEq,
tail: Cons {
head: RustSerialize,
tail: Cons { head: RustDeserialize, tail: Empty }
}
}
}
}
}
}
}

fn map_key_required_derive_traits() -> List<RustCapability> {
Cons { head: RustEq, tail: Cons { head: RustHash, tail: Empty } }
}

fn kernel_int_arithmetic_traits() -> List<RustCapability> {
Cons {
head: RustAdd,
tail: Cons {
head: RustSub,
tail: Cons {
head: RustMul,
tail: Cons {
head: RustDiv,
tail: Cons {
head: RustRem,
tail: Cons {
head: RustNeg,
tail: Cons {
head: RustPartialEq,
tail: Cons { head: RustPartialOrd, tail: Empty }
}
}
}
}
}
}
}
}


data rust_capability_list_ops_home_note: String = "derive_traits_contain and derive_traits_union live HERE, typed on the closed RustCapability alphabet, and not in std.trait_derive_shape. They arrived in this migration by relocation rather than by authoring: in std they were typed on the OPEN TargetCapabilityKey brand while their only consumer, v1.compiler.trait_derive_emit v1_with_map_key_requirement, threads RustCapability end to end -- so the signature laundered the closed alphabet into the open key space, which is exactly the guarantee the alphabet exists to hold (DESIGN section 4b). Caught in review, not by the compiler. THE ALTERNATIVE REPAIR WAS WORSE AND IS RECORDED SO IT IS NOT RETRIED: keeping them in std and lifting to keys at the call site would have forced the union result back through a key-to-spelling step that no longer exists, since spelling is total only over the alphabet. DECLARED SECTION 2 RESIDUE: these are a set-union and a membership test over a list, specialized to one element type because this corpus carries no generic list union to instance. That is duplication waiting to happen -- the next element type that needs a union will either copy these or finally write the generic. Dissolves into a generic std list union when a second element type asks for one; deliberately not minted here, because authoring a new std primitive is a wider change than the review finding that produced this move."

fn derive_traits_contain(
traits: List<RustCapability>,
capability: RustCapability
) -> Bool {
traits |> any(k => k == capability)
}

fn derive_traits_union(
base: List<RustCapability>,
extra: List<RustCapability>
) -> List<RustCapability> {
extra |> fold(init: base, f: (acc, k) =>
if derive_traits_contain(traits: acc, capability: k) { acc } else { concat(acc, [k]) }
)
}
Loading