Skip to content

Commit 78de347

Browse files
refactor(manhattan-recovery): scope recovery + complete grammar refactor + rip dependent-type creep (#19)
* refactor(manhattan-recovery): scope recovery + complete grammar refactor + rip dependent-type creep Major realignment of AffineScript scope back to user intent after accumulated bot scope creep. This commit contains the full 2026-04-10 Manhattan Recovery session work. Scope changes (authoritative thesis now in .machine_readable/anchors/ANCHOR.a2ml and Desktop Frontier Programming Practices guides v2.0): IN SCOPE (8 features — copied-from-family + affine headline): phantom, immutable-by-default, row polymorphism, full type inference, sound type system, effect tracking, affine types, decidable refinements (soft) OUT OF SCOPE (removed or deferred): linear strict types (subsumed by affine — was bot creep) full dependent types (deferred to sibling Typed WASM project) tropical types (deferred to Typed WASM) algebraic effect handlers (extension point — declarations only for now) unbounded refinement (decidability boundary) Code changes: - Complete in-progress grammar refactor: CONST keyword, PLUSPLUS (++) concat, DOTDOT+lower_ident row-tail, trailing commas in records, upper_ident as ExprVar for bare variant constructors - Fix broken build (restore ROW_VAR token wiring after refactor delete) - Rip dependent-type creep: TDepArrow, TNat, KNat, nat_expr, TRefined, predicate, constraint.ml (entire file), TyDepArrow, TyRefined, NatArg, UnsafeAssume, ConstraintPred, ctx.store, lower_nat_expr, lower_predicate, Constraint.* references. ~500 LOC removed across 14 files. Documentation: - ANCHOR.a2ml first write (retroactive — repo predates the ANCHOR convention) - META.a2ml: ADR-001 (split-Gamma canonical), ADR-002 (scaled Let rule), ADR-003 (left-to-right evaluation order) - STATE.a2ml: honest [features] block, BUG-001..BUG-005 logged, [deferred-upgrade] block noting missing 6a2-suite machinery - README.adoc and COMPILER-CAPABILITIES.md: v2.0 honest scope qualifications - docs/spec.md: honest-status header note; large dependent-type and refinement-type sections removed; scattered inline mentions flagged for a future full spec rewrite - Desktop Frontier Programming Practices guides rewritten v2.0 (AI.a2ml + Human_Programming_Guide.adoc) replacing defensive v1.0 drafts - docs/history/TYPECHECKER-COMPLETION-2026-01-23.md (demoted — the 100% claim was measured by dune build passing, not behavioural tests) - Legacy STATE.scm / META.scm / ECOSYSTEM.scm deleted (fresh A2ML counterparts already exist in .machine_readable/6a2/) Formal verification (Track F1): - Idris2 Solo-core formalisation under docs/academic/formal-verification/ solo-core/: Quantity.idr (27 semiring lemmas proven by Refl), Syntax.idr, Context.idr, Typing.idr, Soundness.idr (declared progress + preservation + affinePreservation goals with explicit holes), README.adoc with weekly-check hook against the OCaml implementation Estate-wide feedback memories saved (apply to all language projects): - feedback_bot_scope_creep_free_variant.md -- the "since we already have X, we can trivially add Y" anti-pattern (linear-because-affine, dependent-because-refinement, handlers-because-effects) - feedback_language_scope_in_thesis.md -- scope lives in a written thesis, not in the code. "I don't see my project in the code" is the alarm signal - feedback_completion_vs_behavioural_coverage.md -- "dune build passes" does not equal behavioural test coverage; split rules-vs-wiring metrics Soundness bugs discovered during the audit (fixes in Phase 1+): BUG-001 (high): omega-let smuggles linear values (unscaled Let rule) BUG-002 (medium): :0-let does not erase its RHS BUG-003 (medium): eval_list evaluates right-to-left via List.fold_right BUG-004 (medium): lambda-body usage not tracked against outer captures BUG-005 (medium): WasmGC backend silently drops unknown function calls Phase 0 complete. Phase 1 is wiring the affine quantity checker into the CLI check/compile/eval paths (see STATE.a2ml [track-a-manhattan]). Not yet started. Build: green (dune build). Tests: 22 failures (identical count to pre-rip baseline — zero new regressions). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(manhattan-recovery): update TyArrow arity to 4-args in parser + julia backend The Manhattan Recovery commit bundled the pre-existing grammar refactor that added a quantity field to TyArrow (3-arg -> 4-arg). Two call sites in parser.mly (type_expr_arrow productions) and julia_codegen.ml (type_expr_to_julia_string) were at line locations where the auto-merge with origin/main took upstream's 3-arg version without conflict markers. Post-cherry-pick build fix — adds the missing quantity argument (None) in all three call sites. No semantic change. --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent fec4db0 commit 78de347

43 files changed

Lines changed: 1702 additions & 1234 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ Thumbs.db
1616
/build/
1717
/dist/
1818
/out/
19+
# Idris2 build artifacts (nested, e.g. under formal-verification dirs)
20+
**/solo-core/build/
1921

2022
# Dependencies
2123
/node_modules/

.machine_readable/6a2/META.a2ml

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,196 @@ project = "affinescript"
77
author = "Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>"
88
license = "PMPL-1.0-or-later"
99
standard = "RSR 2026"
10+
11+
# ──────────────────────────────────────────────────────────────────────────────
12+
# Architecture Decision Records
13+
# ──────────────────────────────────────────────────────────────────────────────
14+
# ADRs are numbered sequentially and never renumbered. Superseded ADRs remain
15+
# in place with status = "superseded" and a pointer to the replacement.
16+
# Added 2026-04-10 during Track F1 (Idris2 Solo-core formalisation) — the
17+
# formal-verification track surfaced three decisions about the QTT type system
18+
# that were previously implicit.
19+
20+
[[adr]]
21+
id = "ADR-001"
22+
status = "accepted"
23+
date = "2026-04-10"
24+
title = "Split-Γ is the canonical presentation of the QTT type system"
25+
context = """
26+
The Idris2 Solo-core formalisation (docs/academic/formal-verification/solo-core/)
27+
revealed that docs/spec.md §3.6 presents typing rules against a shared Γ
28+
(writing e.g. T-App with both premises typed under the same Γ), while
29+
lib/quantity.ml runs a post-hoc usage walk that accumulates per-variable
30+
usage summed across subterms. The literature-standard QTT presentation
31+
(Atkey 2018, Granule, Idris2 core) uses explicit context splitting
32+
Γ = Γ₁ + q·Γ₂
33+
at every eliminator position.
34+
35+
Both forms are extensionally equivalent for the Solo core (same programs
36+
accepted/rejected). The difference is purely presentational.
37+
"""
38+
decision = """
39+
Split-Γ is canonical. The spec, the formalisation, and all future
40+
documentation present typing rules in split-Γ form. The post-hoc usage walk
41+
in lib/quantity.ml is an equivalent implementation strategy, documented as
42+
such in a comment, not the definition of the type system.
43+
"""
44+
consequences = """
45+
- docs/spec.md §3.6 is rewritten to show explicit context splitting (~30-60 LOC).
46+
- lib/quantity.ml gets a header comment explaining that its flat walk is an
47+
equivalent implementation of the split-Γ rules, with a pointer to this ADR.
48+
- The Idris2 formalisation's Typing.idr (which uses split-Γ) becomes the
49+
mechanised witness of the spec — no translation layer required.
50+
- Progress + preservation proofs can proceed in textbook form.
51+
- Dependability gain: one source of truth. The spec-vs-impl gap (the failure
52+
mode flagged in Track B's audit of TYPECHECKER-COMPLETION.md) cannot
53+
structurally hide in this part of the system.
54+
- Interop gain: the spec becomes citable and legible to anyone with QTT
55+
background (Atkey, Idris2, Granule, Quill readers).
56+
- Reader-tax cost: split-Γ notation is heavier than shared-Γ for newcomers.
57+
Mitigated by surface-language tutorials keeping informal shared-Γ intuition
58+
while the spec remains the formal reference.
59+
"""
60+
61+
[[adr]]
62+
id = "ADR-002"
63+
status = "accepted"
64+
date = "2026-04-10"
65+
title = "Let rule scales value context by binder quantity (QTT-orthodox)"
66+
context = """
67+
During the Decision-2 audit of docs/spec.md T-Let against lib/typecheck.ml
68+
and lib/quantity.ml, the current implementation was found to handle Let
69+
unsoundly:
70+
71+
- lib/typecheck.ml:631-665 (ExprLet) does zero quantity handling — pure
72+
HM-style inference with let-generalisation, quantities entirely absent.
73+
- lib/quantity.ml:251-253 (ExprLet in infer_usage_expr) does a flat walk
74+
that sums e1's and e2's usages without scaling e1 by the binder's quantity.
75+
76+
This is equivalent to the rule
77+
Γ₁ ⊢ e1 : A (Γ₂, x:A) ⊢ e2 : B
78+
─────────────────────────────────
79+
Γ₁ + Γ₂ ⊢ let x = e1 in e2 : B
80+
rather than the QTT-orthodox
81+
Γ₁ ⊢ e1 : A (Γ₂, x:^q A) ⊢ e2 : B
82+
─────────────────────────────────────
83+
q·Γ₁ + Γ₂ ⊢ let x :^q = e1 in e2 : B
84+
85+
Two concrete soundness bugs follow:
86+
87+
BUG-001 (high severity — linear-value smuggling):
88+
let x :ω = linear_resource() in use_x_once(x)
89+
Current impl accepts; QTT-correct form rejects (e1's Γ must be scaled by
90+
ω, so any Γ₁ containing a linear variable becomes ill-formed).
91+
92+
BUG-002 (medium severity — erasure failure):
93+
let x :0 = expensive_proof_term() in body_not_using_x
94+
Current impl evaluates e1 and consumes its resources; QTT-correct form
95+
scales e1's Γ by 0, producing the zero context, which means e1 can be
96+
erased at runtime.
97+
98+
BUG-001 is a soundness hole that defeats the point of affine types in any
99+
program where ω-binders and linear values coexist.
100+
"""
101+
decision = """
102+
The Let rule in both the spec and the implementation scales the value
103+
context by the binder's quantity. T-Let becomes:
104+
105+
Γ₁ ⊢ e1 : A (Γ₂, x:^q A) ⊢ e2 : B
106+
─────────────────────────────────────
107+
q·Γ₁ + Γ₂ ⊢ let x :^q = e1 in e2 : B
108+
109+
Unannotated Let defaults to q = ω (matching current behaviour for all
110+
existing unannotated code — so the fix is non-breaking for the common case).
111+
"""
112+
consequences = """
113+
- lib/quantity.ml ExprLet case grows a scale-by-q step before summing
114+
into the outer context (~10 LOC).
115+
- lib/typecheck.ml ExprLet case threads quantities (folded into Track A3
116+
which is already rewriting quantity flow through typecheck.ml).
117+
- docs/spec.md T-Let rule is rewritten to show the scaling explicitly.
118+
- Two regression tests added as Track A2 fixtures covering BUG-001 and
119+
BUG-002.
120+
- The Idris2 formalisation (Typing.idr THLet) already assumes the scaled
121+
form — no rework there.
122+
- Users who had previously (accidentally) relied on the unsound behaviour
123+
to duplicate linear values through ω-lets will now get a compile error.
124+
Expected blast radius: near-zero because affine enforcement was never
125+
wired in the first place (see ADR-001 rationale).
126+
"""
127+
128+
[[adr]]
129+
id = "ADR-003"
130+
status = "accepted"
131+
date = "2026-04-10"
132+
title = "Evaluation order is strict CBV, left-to-right, for all n-ary forms"
133+
context = """
134+
During the Decision-3 audit of lib/interp.ml for the Track F1 Step relation,
135+
the evaluator was found to be internally inconsistent about evaluation order
136+
of n-ary expression forms.
137+
138+
- ExprBinary (lib/interp.ml:135-138) is explicitly left-to-right:
139+
let* left_val = eval env left in
140+
let* right_val = eval env right in
141+
eval_binop op left_val right_val
142+
- ExprApp args (:130), ExprTuple (:144), ExprArray (:148) all delegate to
143+
eval_list, which is implemented with List.fold_right:
144+
and eval_list env exprs =
145+
List.fold_right (fun expr acc ->
146+
let* vals = acc in
147+
let* v = eval env expr in
148+
Ok (v :: vals)
149+
) exprs (Ok [])
150+
OCaml is strict, so in f (fold_right f [a;b;c] init) the innermost
151+
application runs first — eval env c is forced before eval env b before
152+
eval env a. Net result: right-to-left.
153+
154+
This was almost certainly unintentional; nothing currently depends on the
155+
order because affine enforcement was never wired. However:
156+
157+
- The WASM and Julia backends will naturally generate left-to-right code,
158+
producing cross-backend semantic divergence for any program with effectful
159+
or resource-consuming arguments.
160+
- The effect system (70% complete per STATE.a2ml) would observe handler
161+
ordering tied to evaluation order, making this a latent soundness hazard.
162+
- A Track F1 Step relation defined in textbook CBV left-to-right form would
163+
disagree with the interpreter, requiring a non-standard right-to-left
164+
presentation or a proof of order-independence (which is false in general
165+
for effectful languages).
166+
"""
167+
decision = """
168+
All n-ary expression forms evaluate their subterms strict left-to-right.
169+
This applies to: application arguments, tuples, arrays, record fields,
170+
function calls in all positions.
171+
172+
lib/interp.ml eval_list is fixed to left-to-right:
173+
and eval_list env exprs =
174+
let rec loop acc = function
175+
| [] -> Ok (List.rev acc)
176+
| e :: rest ->
177+
let* v = eval env e in
178+
loop (v :: acc) rest
179+
in
180+
loop [] exprs
181+
182+
Track F1's Step relation uses the standard CBV left-to-right presentation
183+
e1 → e1' ⟹ e1 e2 → e1' e2 (reduce function first)
184+
e2 → e2' ⟹ v1 e2 → v1 e2' (then argument, only once function is a value)
185+
with the symmetric congruences for pairs, tuples, etc.
186+
"""
187+
consequences = """
188+
- lib/interp.ml eval_list is replaced (~6 LOC diff).
189+
- docs/spec.md gains (or receives an edit to) an explicit operational
190+
semantics section stating strict CBV, left-to-right.
191+
- A regression test lands in Track A2 exercising a program whose output
192+
depends on left-to-right evaluation (e.g. a tuple of two side-effecting
193+
calls that mutate a shared counter).
194+
- WASM, Julia, and the effect system all become consistent with the
195+
interpreter by default — no backend fix required.
196+
- Track F1 can proceed on its current footing to mechanise Step and the
197+
progress/preservation proofs without author input.
198+
- Existing programs are unaffected unless they rely on observable right-
199+
to-left evaluation of tuple/arg components. The interpreter is the only
200+
place that did this, and nobody has filed a bug, so blast radius is
201+
expected to be zero.
202+
"""

.machine_readable/6a2/STATE.a2ml

Lines changed: 153 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,22 @@
44
[metadata]
55
project = "affinescript"
66
version = "0.1.0"
7-
last-updated = "2026-04-04"
7+
last-updated = "2026-04-10"
88
status = "active"
99

1010
[project-context]
1111
name = "affinescript"
12-
completion-percentage = 92
13-
phase = "lsp-phase-b"
12+
completion-percentage = 78
13+
phase = "manhattan-track-a"
1414
tagline = "Rust-inspired language with affine types, dependent types, row polymorphism, and extensible effects"
15+
note = "Track A (Manhattan plan) in progress — affine enforcement landing T+7d. Headline features partially declared-but-unwired; see [features] for honest status."
1516

1617
[components]
17-
lexer = "complete"
18+
lexer = "complete-minus-affine-tokens (ZERO/ONE tokens for quantity literals NOT emitted; blocks QTT surface syntax)"
1819
parser = "complete (1245 conflicts; block_terminator rule added for self-delimiting exprs)"
19-
type-checker = "99% (Never/bottom type handling fixed; block divergence propagation added)"
20-
borrow-checker = "95%"
20+
type-checker-rules = "99% (bidirectional inference, Never/bottom, block divergence, variant/constructor/record-spread/mutable bindings all implemented in lib/typecheck.ml)"
21+
type-checker-enforcement-wiring = "0% (type checker not invoked from bin/main.ml on the check/compile/eval CLI paths; rules exist but do not gate user programs)"
22+
borrow-checker = "phase-3-in-progress (lib/borrow.ml carries [IMPL-DEP: Phase 3] markers; not yet authoritative)"
2123
interpreter = "95%"
2224
wasm-codegen = "92% (real-world game compiles: airborne-submarine-squadron/src/main.affine → 8KB WASM)"
2325
wasm-gc-codegen = "70% (WasmGC proposal target: struct.new/struct.get/array.new_fixed/array.get; --wasm-gc CLI flag)"
@@ -33,3 +35,148 @@ compiler-loc = 12424
3335
compiler-modules = 38
3436
lsp-files = 5
3537
test-files = 54
38+
39+
[features]
40+
# Honest status of the headline language features advertised in README.adoc.
41+
# "declared-but-unwired" = surface syntax and/or internal module exists, but
42+
# the feature is not enforced on user programs through the CLI pipeline.
43+
affine-types = "declared-but-unwired (quantity semiring exists in lib/quantity.ml but is never called from bin/main.ml; lexer does not emit ZERO/ONE tokens; enforcement landing via Track A Manhattan plan, ETA T+7d)"
44+
linear-arrows = "parse-only (-[q]-> syntax accepted by parser; quantity annotation not propagated into enforcement)"
45+
borrow-checker = "phase-3-in-progress (see lib/borrow.ml [IMPL-DEP: Phase 3])"
46+
row-polymorphism = "60% (records + effects rows implemented in typecheck/unify; not fully exercised end-to-end)"
47+
effects = "declarations-only (effect types parsed and tracked; handler semantics not yet in interpreter or backends)"
48+
dependent-types = "parse-only (TRefined AST node exists and refinement predicates parse, but predicates do not reduce; no SMT/decision procedure wired in)"
49+
traits = "70% (registry and lookup work; generic trait resolution needs unification integration)"
50+
51+
[track-a-manhattan]
52+
owner = "primary"
53+
scope = "wire the quantity checker into CLI check/compile/eval paths; emit ZERO/ONE tokens from lexer; close the declared-but-unwired gap on affine types"
54+
spine-files = ["lib/lexer.ml", "lib/parser.mly", "lib/token.ml", "lib/typecheck.ml", "lib/quantity.ml", "bin/main.ml", "lib/interp.ml"]
55+
eta = "T+7d from 2026-04-10"
56+
57+
[[open-bug]]
58+
id = "BUG-001"
59+
severity = "high"
60+
category = "soundness"
61+
title = "ω-let smuggles linear values"
62+
discovered = "2026-04-10"
63+
description = """
64+
let x :ω = linear_resource() in use_x_once(x) is currently accepted.
65+
QTT-correct form rejects — see ADR-002. The current implementation does not
66+
scale the Let value context by the binder quantity, so a linear value captured
67+
in e1 can be bound at ω and duplicated in e2.
68+
"""
69+
evidence = "lib/quantity.ml:251-253 (flat walk, no scaling); lib/typecheck.ml:631-665 (zero quantity handling)"
70+
fix-plan = "Track A3 — fold Let scaling into the quantity-wiring work. See ADR-002."
71+
regression-test = "Track A2 — add fixture examples/bug_001_omega_let_smuggles_linear.affine (must be rejected)."
72+
73+
[[open-bug]]
74+
id = "BUG-002"
75+
severity = "medium"
76+
category = "semantics"
77+
title = ":0 lets do not erase their RHS"
78+
discovered = "2026-04-10"
79+
description = """
80+
let x :0 = expensive_proof_term() in body_not_using_x currently evaluates
81+
expensive_proof_term() and consumes its resources. QTT-correct form scales
82+
e1's context by 0, producing the zero context, which means e1 can be erased
83+
at runtime. Not a soundness hole but defeats the erasure story.
84+
"""
85+
evidence = "lib/quantity.ml:251-253; lib/interp.ml ExprLet always evaluates the RHS"
86+
fix-plan = "Track A3 semantics fix lands with BUG-001. Interpreter may additionally skip eval of :0-bound RHS (opt-in, deferrable)."
87+
regression-test = "Track A2 — add fixture examples/bug_002_zero_let_erasure.affine (non-terminating RHS bound at :0 must terminate)."
88+
89+
[[open-bug]]
90+
id = "BUG-003"
91+
severity = "medium"
92+
category = "semantics"
93+
title = "eval_list evaluates right-to-left via List.fold_right"
94+
discovered = "2026-04-10"
95+
description = """
96+
lib/interp.ml:348 eval_list uses List.fold_right with monadic bind, which
97+
in strict OCaml evaluates arguments right-to-left. ExprBinary at :135-138 is
98+
left-to-right. This creates internal evaluator inconsistency and future
99+
backend/interpreter divergence once effects or affine enforcement land.
100+
See ADR-003.
101+
"""
102+
evidence = "lib/interp.ml:348-353 (fold_right); lib/interp.ml:135-138 (L-to-R binop by contrast)"
103+
fix-plan = "Track A3 — fix eval_list to strict L-to-R (~6 LOC). See ADR-003."
104+
regression-test = "Track A2 — add fixture examples/bug_003_eval_order.affine with observable L-to-R ordering via a shared counter."
105+
106+
[[open-bug]]
107+
id = "BUG-004"
108+
severity = "medium"
109+
category = "soundness"
110+
title = "Lambda-body usage not tracked against outer captures"
111+
discovered = "2026-04-10"
112+
description = """
113+
lib/quantity.ml:245-249 explicitly documents that lambda-bound params are
114+
not tracked and that 'the lambda body may still reference outer tracked
115+
variables' — but the current code does not charge usage against those
116+
captures. A lambda capturing a linear variable can be called multiple times,
117+
duplicating the captured resource.
118+
"""
119+
evidence = "lib/quantity.ml:245-249 (comment admits the gap)"
120+
fix-plan = "Track D (borrow checker Phase 3) — lambda capture analysis is part of the borrow/ownership story. Not A3 scope."
121+
regression-test = "Track D fixture — deferred until borrow checker lands."
122+
123+
[[open-bug]]
124+
id = "BUG-005"
125+
severity = "medium"
126+
category = "codegen"
127+
title = "WasmGC backend silently drops unknown function calls"
128+
discovered = "2026-04-10"
129+
description = """
130+
lib/codegen_gc.ml ExprApp handling silently emits 'drop all args + push null'
131+
when the callee is not in the func_indices table, and does the same for
132+
indirect calls. This is placeholder behaviour that produces wrong code rather
133+
than failing loudly. Any program that reaches codegen with an unresolved
134+
function call will compile to nonsense at runtime.
135+
"""
136+
evidence = "lib/codegen_gc.ml gen_gc_expr ExprApp case (the 38-line block added as part of the in-progress WasmGC work)"
137+
fix-plan = "Replace silent drops with explicit CodegenError. Direct-call path (via func_indices) and int/float builtin coercions stay — they're correct. Only the fallback arms need to fail loudly."
138+
regression-test = "Add a fixture that intentionally references an unknown function name and expects a loud compile error."
139+
140+
# ─── Deferred upgrade: bring .machine_readable/ to current standards ──────────
141+
# AffineScript predates most of the current hyperpolymath .machine_readable/
142+
# suite. The 6a2 core is present; the surrounding machinery is not. This is
143+
# logged as deferred work, separate from the Manhattan recovery, to avoid
144+
# scope creep into that plan.
145+
146+
[deferred-upgrade]
147+
session = "separate, not Phase 0"
148+
estimated-effort = "1-2 focused hours"
149+
150+
present:
151+
# What AffineScript already has
152+
present = [
153+
".machine_readable/6a2/AGENTIC.a2ml",
154+
".machine_readable/6a2/ECOSYSTEM.a2ml",
155+
".machine_readable/6a2/META.a2ml",
156+
".machine_readable/6a2/NEUROSYM.a2ml",
157+
".machine_readable/6a2/PLAYBOOK.a2ml",
158+
".machine_readable/6a2/STATE.a2ml",
159+
".machine_readable/anchors/ANCHOR.a2ml", # added 2026-04-10 as first anchor
160+
"contractiles/ (root-level, old location) — dust, k9, lust, must, trust"
161+
]
162+
163+
missing = [
164+
".machine_readable/CLADE.a2ml",
165+
".machine_readable/contractiles/ (should migrate from root contractiles/)",
166+
".machine_readable/contractiles/adjust/",
167+
".machine_readable/contractiles/intend/",
168+
".machine_readable/agent_instructions/",
169+
".machine_readable/integrations/",
170+
".machine_readable/ADJUST.contractile (top-level instance)",
171+
".machine_readable/INTENT.contractile (top-level instance)",
172+
".machine_readable/MUST.contractile (top-level instance)",
173+
".machine_readable/TRUST.contractile (top-level instance)"
174+
]
175+
176+
notes = """
177+
Root-level contractiles/ directory has 5 of 7 current types. The canonical
178+
pattern is .machine_readable/contractiles/ with all 7 types. Migration is
179+
deferred to a separate session because it requires reading each contractile
180+
definition from the standards repo and deciding which apply to AffineScript
181+
specifically. Do not conflate with Manhattan Phase 0.
182+
"""

0 commit comments

Comments
 (0)