Skip to content

Commit e86e8f5

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/pr-294-ragged-path-validation-170zcy
# Conflicts: # .claude/board/LATEST_STATE.md
2 parents 8615f13 + c0bf3aa commit e86e8f5

2 files changed

Lines changed: 76 additions & 0 deletions

File tree

‎.claude/board/LATEST_STATE.md‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,38 @@ stride, slot index, or carving width in any public Java signature
4444
(`WideFieldMask.ofFacets(int…)`, the 97 `LgjLaneDesc` lanes, the `*At`
4545
accessors are the leaks). The wall passes handles, classids, names,
4646
counts, statuses.
47+
## 2026-09-04 — the T2/T3 membrane gets its gate: ApiSurfaceTest fences the raw register + names every breach
48+
49+
**Branch `claude/membrane-tiers-bbb-fence`**, test-only. The paired doctrine +
50+
wardens land in lance-graph (`.claude/knowledge/membrane-tiers.md`,
51+
`kernel-membrane-warden`, `bbb-warden`) so every consumer inherits them; this
52+
is the enforcement half in the repo that owns the Java surface.
53+
54+
`ApiSurfaceTest` already forbade FFM / membrane types in any public signature.
55+
Two additive rules extend it to the T2/T3 membrane (names cross, byte positions
56+
never do):
57+
58+
1. **Raw-register fence** — a `byte[]` in any public signature (return, param,
59+
field) is a raw content register (a `[u8;12]` rail array / payload bytes)
60+
crossing the consumer wall. Caught in `check()` on the array component type
61+
(the package-prefix match never sees a primitive component). Ledger L6.
62+
2. **Named-breach rule** — a public method returning ANY array must be named
63+
`materialize*` or `import*`; folds the GraphHopTest allowlist into the
64+
compiled-surface scan so a bridge/inherited array return can't slip a source
65+
grep. Ledger L7.
66+
67+
Green on the current surface by construction: only `Mask.materializeRows()`
68+
returns an array (named), and no public `byte[]` exists (`RowLayout.sets` is
69+
private, unscanned). The two predicates' behaviour was proven standalone (a
70+
byte[] return and param are flagged; an unnamed `int[]` return is flagged;
71+
`materialize*`/`import*` pass) — 5/5. The full Java suite was NOT run in-session
72+
(env has JDK 21; the repo targets JDK 27 + preview FFM + Valhalla) — CI runs it.
73+
74+
**What this gate does NOT prove (honest, per membrane-tiers.md):** reflection
75+
cannot tell `int classid` (a name, clean) from `int facet` (a slot index, a
76+
leak) — same type. `WideFieldMask.ofFacets(int... positions)` (L1) and the
77+
served `LgjLaneDesc` strides (L2) are the semantic leaks the `bbb-warden`
78+
reviews; the gate catches the mechanical subset only.
4779

4880
## 2026-09-03 — mask-risc-lowering ratified and then AMENDED: the vertical axis is enumerated, not cached
4981

‎java/src/test/java/com/adaworldapi/lancegraph/ApiSurfaceTest.java‎

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,36 @@ public static void run(Checks c) {
8383
}
8484
}
8585

86+
c.section("the T2/T3 membrane: no raw register crosses, and every array is a named breach");
87+
// Doctrine: .claude/knowledge/membrane-tiers.md (T2/T3). A public consumer
88+
// surface may carry NAMES (handle, classid, field name, version), counts and
89+
// statuses — never a raw content register (byte[] = a [u8;12] rail/payload) and
90+
// never an un-named array population. `byte[]` is folded into FORBIDDEN above.
91+
// Array returns are the row-id/slot-index leak: allowed ONLY from a method whose
92+
// name announces the crossing (materialize* out, import* in) — the GraphHopTest
93+
// allowlist, enforced here on the COMPILED surface so a bridge/inherited return
94+
// cannot slip it past a source grep.
95+
List<String> unnamedArrays = new ArrayList<>();
96+
for (Class<?> type : types) {
97+
for (Method m : type.getMethods()) {
98+
if (!isPublicApi(m) || m.getDeclaringClass() == Object.class) {
99+
continue;
100+
}
101+
if (m.getReturnType().isArray() && !isNamedBreach(m.getName())) {
102+
unnamedArrays.add(type.getSimpleName() + "." + m.getName()
103+
+ " returns " + m.getReturnType().getSimpleName()
104+
+ " but its name does not start with materialize/import");
105+
}
106+
}
107+
}
108+
if (unnamedArrays.isEmpty()) {
109+
c.that("every array-returning public method names its crossing (materialize*/import*)", true);
110+
} else {
111+
for (String u : unnamedArrays) {
112+
c.that("UNNAMED-BREACH: " + u, false);
113+
}
114+
}
115+
86116
c.section("the escape hatch is named, not incidental");
87117
// Raw native access must require deliberately reaching into an internal package. It must
88118
// never be something ordinary composition hands you.
@@ -135,6 +165,7 @@ private static boolean isPublicApi(Executable e) {
135165

136166
private static void check(List<String> leaks, Class<?> owner, String where, Class<?> t) {
137167
Class<?> component = t;
168+
boolean isArray = t.isArray();
138169
while (component.isArray()) {
139170
component = component.getComponentType();
140171
}
@@ -144,6 +175,19 @@ private static void check(List<String> leaks, Class<?> owner, String where, Clas
144175
leaks.add(owner.getSimpleName() + "." + where + " is " + name);
145176
}
146177
}
178+
// T2/T3 membrane: a byte[] in any public signature is a raw content register
179+
// (a [u8;12] rail array / payload bytes) crossing the wall — the substrate
180+
// wearing a collection. Names cross; registers never do.
181+
// (.claude/knowledge/membrane-tiers.md ledger L6.)
182+
if (isArray && component == byte.class) {
183+
leaks.add(owner.getSimpleName() + "." + where
184+
+ " is byte[] (a raw content register may not cross the consumer membrane)");
185+
}
186+
}
187+
188+
/** A crossing whose method name announces it — the only sanctioned materialiser/importer. */
189+
private static boolean isNamedBreach(String methodName) {
190+
return methodName.startsWith("materialize") || methodName.startsWith("import");
147191
}
148192

149193
/** Enumerate public types by listing the compiled package directory on the classpath. */

0 commit comments

Comments
 (0)