|
| 1 | += AffineScript ↔ aLib Conformance & Contribution Roadmap |
| 2 | +:toc: macro |
| 3 | +:toclevels: 3 |
| 4 | +:icons: font |
| 5 | + |
| 6 | +25 items across three tiers, structuring AffineScript's relationship |
| 7 | +with `hyperpolymath/aggregate-library` (aLib): conformance |
| 8 | +*implementation* (passing aLib's test vectors), conformance |
| 9 | +*infrastructure* (runner, reporting, CI), and *contributions* of |
| 10 | +affine-aware semantics back to aLib upstream. |
| 11 | + |
| 12 | +[IMPORTANT] |
| 13 | +==== |
| 14 | +This document complements link:ROADMAP.adoc[ROADMAP.adoc] (language / |
| 15 | +compiler progress), link:bindings-roadmap.adoc[bindings-roadmap.adoc] |
| 16 | +(framework bindings), and link:stdlib-roadmap.adoc[stdlib-roadmap.adoc] |
| 17 | +(standard library). Where this file disagrees with |
| 18 | +link:CAPABILITY-MATRIX.adoc[CAPABILITY-MATRIX.adoc] or |
| 19 | +link:ECOSYSTEM.adoc[ECOSYSTEM.adoc], those documents win. |
| 20 | +
|
| 21 | +Compiled 2026-05-28 from a fresh read of |
| 22 | +link:https://github.com/hyperpolymath/aggregate-library[hyperpolymath/aggregate-library] |
| 23 | +v0.1.0 + estate-wide use of the aLib methodology. |
| 24 | +==== |
| 25 | + |
| 26 | +toc::[] |
| 27 | + |
| 28 | +== What aLib is — and is not |
| 29 | + |
| 30 | +`hyperpolymath/aggregate-library` is a *methods repository*, not a |
| 31 | +stdlib replacement. It demonstrates how to: |
| 32 | + |
| 33 | +* identify a minimal overlap between systems with very different |
| 34 | + constraints, |
| 35 | +* express that overlap as a stable spec surface + semantics notes + |
| 36 | + conformance test suite, |
| 37 | +* enforce reversibility through disciplined boundaries and test |
| 38 | + vectors. |
| 39 | + |
| 40 | +The current overlap is intentionally small — 20 operations across 6 |
| 41 | +categories — chosen to *stress-test the method*, not to be a "shared |
| 42 | +stdlib". |
| 43 | + |
| 44 | +[cols="1,3"] |
| 45 | +|=== |
| 46 | +|Category |Operations |
| 47 | + |
| 48 | +|arithmetic |add, subtract, multiply, divide, modulo, negate, absolute, max, min |
| 49 | +|comparison |(per `aggregate.json` — 1+ ops; coverage spec) |
| 50 | +|logical |(per `aggregate.json`) |
| 51 | +|string |concat, length, reverse, substring |
| 52 | +|collection |contains, empty, filter, fold, length, map |
| 53 | +|conditional |(per `aggregate.json`) |
| 54 | +|=== |
| 55 | + |
| 56 | +NOTE: Counts above are from `data/aggregate.json` v1.1.0 (generated |
| 57 | +2025-12-27, 20 total operations). When aLib publishes a new version, |
| 58 | +this table updates here in the same PR that bumps the consumed |
| 59 | +version. |
| 60 | + |
| 61 | +== Reading guide |
| 62 | + |
| 63 | +Each entry carries: |
| 64 | + |
| 65 | +* *Status* — `○` nothing built, `◐` scaffold, `◑` partial, `●` usable. |
| 66 | +* *Track* — `T1` implementation, `T2` runner/infra, `T3` contributions. |
| 67 | +* *Rationale* — what the item delivers, and which downstream consumer |
| 68 | + benefits. |
| 69 | + |
| 70 | +Item numbers are stable across revisions. |
| 71 | + |
| 72 | +== Tier 1 — Conformance implementation |
| 73 | + |
| 74 | +Implement the 20 operations in AffineScript such that aLib's test |
| 75 | +vectors pass. Most ops *already* exist in `stdlib/` partially; the |
| 76 | +work here is alignment with aLib's `signature_string`, semantics, and |
| 77 | +edge-case requirements. |
| 78 | + |
| 79 | +[cols="1,3,1,2,5"] |
| 80 | +|=== |
| 81 | +|# |Item |Status |Track |Rationale |
| 82 | + |
| 83 | +|1 |
| 84 | +|*Arithmetic-9 implementation* — `add`, `subtract`, `multiply`, `divide`, `modulo`, `negate`, `absolute`, `max`, `min` aligned with `specs/arithmetic/*.md` |
| 85 | +|`◑` partial |
| 86 | +|T1 |
| 87 | +|`stdlib/math.affine` covers most; verify signatures match aLib + properties (commutative, associative, identity) hold. |
| 88 | + |
| 89 | +|2 |
| 90 | +|*Comparison ops* — `eq`, `ne`, `lt`, `le`, `gt`, `ge` per `specs/comparison/` |
| 91 | +|`◑` partial |
| 92 | +|T1 |
| 93 | +|Trait surface; pairs with `traits.affine` (stdlib #18). |
| 94 | + |
| 95 | +|3 |
| 96 | +|*Logical ops* — `and`, `or`, `not`, `xor` per `specs/logical/` |
| 97 | +|`◑` partial |
| 98 | +|T1 |
| 99 | +|Mostly built-in operators; conformance is verifying short-circuit + truth-table behaviour matches aLib semantics. |
| 100 | + |
| 101 | +|4 |
| 102 | +|*String-4 implementation* — `concat`, `length`, `reverse`, `substring` per `specs/string/*.md` |
| 103 | +|`◑` partial |
| 104 | +|T1 |
| 105 | +|`stdlib/string.affine` exists; runtime gaps (stdlib roadmap #8, #9) are upstream blockers. |
| 106 | + |
| 107 | +|5 |
| 108 | +|*Collection-6 implementation* — `contains`, `empty`, `filter`, `fold`, `length`, `map` per `specs/collection/*.md` |
| 109 | +|`◑` partial |
| 110 | +|T1 |
| 111 | +|`stdlib/collections.affine` exists; runtime gaps (stdlib roadmap #1, #2) are upstream blockers. Generic over list at minimum; ideally generic over `Foldable`. |
| 112 | + |
| 113 | +|6 |
| 114 | +|*Conditional op* — `if-then-else` as expression per `specs/conditional/` |
| 115 | +|`●` usable |
| 116 | +|T1 |
| 117 | +|Language built-in; verify spec semantics match. |
| 118 | + |
| 119 | +|7 |
| 120 | +|*Edge-case coverage* — implement and test NaN, infinity, overflow, empty-string, empty-list edge cases per each op's `edge_cases` field |
| 121 | +|`○` |
| 122 | +|T1 |
| 123 | +|aLib specs intentionally leave overflow / NaN "implementation-defined" but require *documented* behaviour. AffineScript declares its choice here. |
| 124 | + |
| 125 | +|8 |
| 126 | +|*Properties verification* — `add` is commutative, `multiply` is associative, `abs` is idempotent, etc. |
| 127 | +|`○` |
| 128 | +|T1 |
| 129 | +|aLib `semantics.properties` is the contract; AffineScript proves (or property-tests) each. |
| 130 | + |
| 131 | +|9 |
| 132 | +|*Signature alignment audit* — every AffineScript op's signature matches the aLib `signature_string` |
| 133 | +|`○` |
| 134 | +|T1 |
| 135 | +|Mechanical comparison; ensures cross-language portability of code written against the aLib surface. |
| 136 | + |
| 137 | +|10 |
| 138 | +|*Conformance module* — `stdlib/alib.affine` re-exporting the 20 ops under their aLib names |
| 139 | +|`○` |
| 140 | +|T1 |
| 141 | +|Single import point for consumers wanting the *aLib surface* rather than the *AffineScript-idiomatic surface*. |
| 142 | +|=== |
| 143 | + |
| 144 | +== Tier 2 — Conformance runner & infrastructure |
| 145 | + |
| 146 | +Build the machinery that *runs* aLib's test vectors against |
| 147 | +AffineScript implementations and reports results. This is what makes |
| 148 | +aLib's "method" actually testable for our language. |
| 149 | + |
| 150 | +[cols="1,3,1,2,5"] |
| 151 | +|=== |
| 152 | +|# |Item |Status |Track |Rationale |
| 153 | + |
| 154 | +|11 |
| 155 | +|*`aggregate.json` schema loader* — parse aLib's v1.1.0 schema in AffineScript (or via build tool) |
| 156 | +|`○` |
| 157 | +|T2 |
| 158 | +|First step; feeds every later runner item. |
| 159 | + |
| 160 | +|12 |
| 161 | +|*Test-vector executor* — iterate `operations[].test_cases[]`, dispatch to the corresponding `alib.affine` op, compare output |
| 162 | +|`○` |
| 163 | +|T2 |
| 164 | +|Core conformance loop. |
| 165 | + |
| 166 | +|13 |
| 167 | +|*Properties auto-checker* — for each declared property (e.g. commutative), run randomized inputs and assert |
| 168 | +|`○` |
| 169 | +|T2 |
| 170 | +|Pairs with item #8; property-based testing under the hood. |
| 171 | + |
| 172 | +|14 |
| 173 | +|*Conformance report emitter* — JSON + a2ml output: per-op pass/fail, properties verified, edge cases covered |
| 174 | +|`○` |
| 175 | +|T2 |
| 176 | +|Estate convention: a2ml machine-readable; JSON for human / CI. |
| 177 | + |
| 178 | +|15 |
| 179 | +|*CI workflow* — `.github/workflows/alib-conformance.yml` runs the suite on every PR, posts a status check |
| 180 | +|`○` |
| 181 | +|T2 |
| 182 | +|Stops drift; visible signal. |
| 183 | + |
| 184 | +|16 |
| 185 | +|*Conformance badge* — README badge + `docs/CAPABILITY-MATRIX.adoc` row showing "aLib conformance: 18/20" |
| 186 | +|`○` |
| 187 | +|T2 |
| 188 | +|Pairs with #15. |
| 189 | + |
| 190 | +|17 |
| 191 | +|*Multi-target harness* — run conformance against the native interp *and* the wasm codegen target, separately |
| 192 | +|`○` |
| 193 | +|T2 |
| 194 | +|Verifies that "type-checks" and "executes" are both green at the aLib surface — directly mitigates the PR #107 class of issue (check PASS / eval FAIL). |
| 195 | + |
| 196 | +|18 |
| 197 | +|*Conformance-comparison view* — side-by-side AffineScript vs reference implementations (phronesis, Rust, Haskell) where available |
| 198 | +|`○` |
| 199 | +|T2 |
| 200 | +|Pairs with `COMPOSITION-GUIDE.md` in aLib; useful for "did we break parity" diagnosis. |
| 201 | +|=== |
| 202 | + |
| 203 | +== Tier 3 — Contributions back to aLib upstream |
| 204 | + |
| 205 | +AffineScript's distinctive properties (affine resource types, |
| 206 | +row-polymorphic effects, dependent types, reversibility) suggest spec |
| 207 | +extensions that aLib doesn't currently capture. These items propose |
| 208 | +*upstream PRs* to `hyperpolymath/aggregate-library`. |
| 209 | + |
| 210 | +[cols="1,3,1,2,5"] |
| 211 | +|=== |
| 212 | +|# |Item |Status |Track |Rationale |
| 213 | + |
| 214 | +|19 |
| 215 | +|*Affine-witness column* — `semantics.affine_consumes: [inputIndices]` in `aggregate.json` schema |
| 216 | +|`○` |
| 217 | +|T3 |
| 218 | +|For each op, declare which inputs are *consumed* vs *borrowed*. Trivially `[]` for current ops (all pure), but the schema extension lands now so future op contributions can use it. Upstream PR to aLib repo. |
| 219 | + |
| 220 | +|20 |
| 221 | +|*Linearity / reversibility tagging* — `semantics.reversible: bool` + `semantics.inverse_op: string` (e.g. `subtract` is inverse of `add`) |
| 222 | +|`○` |
| 223 | +|T3 |
| 224 | +|aLib already mentions "Reversibility" in its design principles but doesn't formalise per-op. Upstream PR; idaptik DLC use case is the motivating consumer. |
| 225 | + |
| 226 | +|21 |
| 227 | +|*Effect-row metadata* — `semantics.effect_row: [labels]` (`Net`, `Fs`, `Random`, `Time`, `IO`) |
| 228 | +|`○` |
| 229 | +|T3 |
| 230 | +|All current 20 ops are pure (`[]`); extension lands the schema field for future capability-aware contributions. Pairs with stdlib roadmap #42, #43. |
| 231 | + |
| 232 | +|22 |
| 233 | +|*Idempotency property* — formalise `semantics.properties[Idempotent]` (`abs(abs(x)) = abs(x)`) |
| 234 | +|`○` |
| 235 | +|T3 |
| 236 | +|aLib semantics.properties has `Commutative`, `Associative`, `Identity element`; idempotency is missing. Upstream PR. |
| 237 | + |
| 238 | +|23 |
| 239 | +|*Monotonicity property* — `semantics.properties[Monotonic]` for `max` / `min` / `length` / `absolute` |
| 240 | +|`○` |
| 241 | +|T3 |
| 242 | +|Same family as #22; missing property class. |
| 243 | + |
| 244 | +|24 |
| 245 | +|*Affine-friendly op proposals* — propose `take` / `drop` / `split` / `join` as collection ops that consume their input (affine-friendly) |
| 246 | +|`○` |
| 247 | +|T3 |
| 248 | +|Current `filter` / `map` / `fold` are all *borrow* shapes; AffineScript's affine surface would benefit from explicit-consume variants. Upstream proposal. |
| 249 | + |
| 250 | +|25 |
| 251 | +|*ADR for affine extension* — single ADR in aLib documenting the schema extensions in #19/#20/#21/#22/#23 + the rationale |
| 252 | +|`○` |
| 253 | +|T3 |
| 254 | +|Bundle the schema-extension items into one upstream PR with proper rationale, so aLib maintainers can review the *whole shape* rather than five disconnected fields. |
| 255 | +|=== |
| 256 | + |
| 257 | +== Cross-cutting observations |
| 258 | + |
| 259 | +. *aLib is small by design.* 20 ops is the entire surface today. The |
| 260 | + conformance work (T1 + T2) is therefore *bounded* — completable in |
| 261 | + a handful of PRs, not a multi-quarter epic. |
| 262 | +. *T3 contributions are the higher-leverage half.* AffineScript's |
| 263 | + affine + effect + dependent type system suggests spec features aLib |
| 264 | + doesn't yet have. Contributing the *method extensions* upstream is |
| 265 | + where AffineScript adds value back, not just consumes. |
| 266 | +. *T1 items #4 and #5 are upstream-blocked* on stdlib roadmap #1, #2, |
| 267 | + #8, #9 (runtime gaps for `List.++`, `List.len`, `String.concat`, |
| 268 | + `String.length`). Don't try to do T1 collection/string conformance |
| 269 | + before those runtime gaps close. |
| 270 | +. *Multi-target harness (T2 #17) is the antidote to the |
| 271 | + PR #107 problem.* Currently `affinescript check` and `affinescript |
| 272 | + eval` can diverge; running conformance against *both* targets |
| 273 | + catches the gap automatically. |
| 274 | +. *aLib license is `MIT OR Palimpsest-0.8`*; AffineScript is MPL-2.0. |
| 275 | + Contributions upstream are spec-level (no code transfer); no |
| 276 | + license-compat issue. |
| 277 | + |
| 278 | +== Suggested sequencing |
| 279 | + |
| 280 | +[cols="1,2,5"] |
| 281 | +|=== |
| 282 | +|Phase |Goal |Items |
| 283 | + |
| 284 | +|*A* |
| 285 | +|Conformance scaffolding |
| 286 | +|#10 (`alib.affine` module) → #11 (schema loader) → #12 (test-vector executor) |
| 287 | + |
| 288 | +|*B* |
| 289 | +|Pure ops first |
| 290 | +|#1 (arithmetic-9) → #6 (conditional) → #2 (comparison) → #3 (logical) — these don't need runtime list/string fixes |
| 291 | + |
| 292 | +|*C* |
| 293 | +|Collection + string ops |
| 294 | +|*Gated on stdlib roadmap A* (List/String runtime). Then #4 + #5 + #7 + #8 + #9. |
| 295 | + |
| 296 | +|*D* |
| 297 | +|CI + visibility |
| 298 | +|#15 (workflow) → #16 (badge) → #17 (multi-target) → #14 (reports) → #18 (comparison view) |
| 299 | + |
| 300 | +|*E* |
| 301 | +|Upstream contributions |
| 302 | +|#25 (ADR draft) → #19/#20/#21/#22/#23 as one upstream PR → #24 (affine-op proposals as a follow-up) |
| 303 | +|=== |
| 304 | + |
| 305 | +== Tracking |
| 306 | + |
| 307 | +* Umbrella tracker: (TBD — opened alongside this PR) |
| 308 | +* Per-tier child issues: (TBD — opened alongside this PR) |
| 309 | +* Upstream tracking: `hyperpolymath/aggregate-library` (T3 items |
| 310 | + result in PRs there, not in this repo) |
| 311 | + |
| 312 | +When an item's status changes, update its row in this file in the |
| 313 | +*same* PR that lands the change; do not let the table drift. |
| 314 | + |
| 315 | +== See also |
| 316 | + |
| 317 | +* link:ROADMAP.adoc[ROADMAP.adoc] — language / compiler progress. |
| 318 | +* link:bindings-roadmap.adoc[bindings-roadmap.adoc] — framework |
| 319 | + bindings (host-runtime FFI surfaces). |
| 320 | +* link:stdlib-roadmap.adoc[stdlib-roadmap.adoc] — standard library |
| 321 | + items (runtime, RSR rewires, universals). |
| 322 | +* link:CAPABILITY-MATRIX.adoc[CAPABILITY-MATRIX.adoc] — per-feature |
| 323 | + readiness (overrides everything). |
| 324 | +* link:https://github.com/hyperpolymath/aggregate-library[aggregate-library] |
| 325 | + — upstream methodology repo. |
| 326 | +* link:https://github.com/hyperpolymath/aggregate-library/blob/main/COMPOSITION-GUIDE.md[aLib COMPOSITION-GUIDE] |
| 327 | + — the method of aggregation across phronesis/Rust/Haskell. |
| 328 | + |
| 329 | +== License |
| 330 | + |
| 331 | +SPDX-License-Identifier: MPL-2.0 |
0 commit comments