Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
fe58c00
Surfaces describe themselves where they refuse, and the kernel stops …
OpenCnid Jul 25, 2026
d0eb667
Compress the two long contribution lines to orienting length
OpenCnid Jul 25, 2026
6daebe9
Declare the frame code on the LM capabilities, and bind the list to t…
OpenCnid Jul 25, 2026
219b76a
Drill the contribution frame, and stop two drills checking a copy of …
OpenCnid Jul 25, 2026
dcb7bbc
Record the build where it belongs, and correct two figures that did n…
OpenCnid Jul 25, 2026
34538be
Wire all thirteen surfaces, and drive the roster off the seam instead…
OpenCnid Jul 25, 2026
89cab46
Tell the run which protocol modules it is operating under
OpenCnid Jul 25, 2026
9914429
Strike the drift half of the self-play gate on the collaborator's ruling
OpenCnid Jul 25, 2026
358f148
Fix the surfaces negative control, which threw instead of detecting
OpenCnid Jul 25, 2026
db50eb9
Correct the ladder table, which went stale inside the record that int…
OpenCnid Jul 25, 2026
0dda689
A ground block carries relevant context only; an expectation goes to …
OpenCnid Jul 25, 2026
d86d920
The modules header stops asserting an operator act it cannot establish
OpenCnid Jul 25, 2026
3dd6134
Three checks that reported a property and held something weaker now h…
OpenCnid Jul 25, 2026
350be94
Retire the instance count that had become the denominator of five checks
OpenCnid Jul 25, 2026
0704303
The citation-closure line stops forbidding what the engine permits
OpenCnid Jul 25, 2026
88f14f3
The author path composes its surface's line instead of shipping a typ…
OpenCnid Jul 25, 2026
41eff03
The default module stops prescribing a write the provenance guard ref…
OpenCnid Jul 25, 2026
3383ede
The pair parser reads JSON lists, and the flywheel repair is measured
OpenCnid Jul 26, 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
4 changes: 4 additions & 0 deletions .claude/skills/judge-composition/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ Pre-register expected verdicts **before** the run, in a timestamped place the pr

Impartiality comes from the judges' isolated clean contexts, not from your prompting. Each judge runs as an isolated sub-agent receiving exactly: an identity preamble, its definition, the evidence its input allowlist permits, and the output schema. Nothing else — not the claimant's identity (authorship is never a parameter — partitioned out by address where the substrate has one, masked in the evidence where it does not), not the other judges, not the composer's expectations, not the purpose of the exercise. **Definitions carry all rigor; task text carries none** — no highlighted questions, no named drawback classes, no embedded expectations.

**The seat's ground block carries relevant context only.** What a cold-started seat needs in order to look is ground — `{Authorship_And_Provenance_Of_The_Bundle}`, `{Addresses_And_Where_To_Read}`, `{What_Counts_As_Evidence_Here}`. What the composer believes the seat will find is not, and it contaminates even when it is true, most of all when it is true: a seat handed a true expectation returns it, and the record cannot separate that from a verdict. One question separates the two — *does this let the seat look, or does it tell the seat what looking will turn up?* — and the probe the composer already ran falls on the second side, which is failure mode 2's channel moving once more: withhold the prediction bytes cleanly and the method that produced them carries the same content while reading as method. A held expectation has one destination and it is not a prompt: the un-tool, the move that ends the tool call and addresses the collaborator instead (`AMBIENT.md` rule 21(a); `.claude/skills/spark-steering/SKILL.md` § *Ask first — the un-tool*).

*(A ceremony spawned four seats over work its own composer had authored and handed one the exact probe by which it had already obtained a pre-registered finding; the seat found it, and the audit seat ruled the run's independence unestablishable — the composer "had already run the probe, saw the result, wrote it down as a prediction, then handed the probe to the seat." Three seats carried composer-stated facts while the composer's disclosure said "three seats" and named two. Separate pre-registration, clean contexts and an audit seat were all in place, so no artifact discharges this; the ground blocks do. The re-run dispatched seven reviewers whose ground blocks carried the facts and stated in as many words that no prediction was offered and none was wanted, and they returned findings the composer had not anticipated, several against the composer's own work.)*

Output schema per item:

```
Expand Down
32 changes: 32 additions & 0 deletions .claude/skills/self-play/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,38 @@ The evaluator's frame additionally withholds the condition label: it judges item
in a single undifferentiated list and never learns which are the "live" ones and
which are controls.

### The `## Ground` block carries relevant context only

Ground is what a player cannot derive from a cold start and needs in order to
look: `{Authorship_And_Provenance_Of_The_Artifact}`,
`{Roster_Addresses_And_Where_To_Read}`, `{What_Counts_As_A_Fact_Here}`. An
expectation — `{What_You_Believe_The_Player_Will_Find}` — is never ground. It
contaminates even when it is true, and most of all when it is true: a player
handed a true expectation hands it back, and nothing in the report separates that
from a finding. The two read alike on the page and separate on one question:
*does this let the player look, or does it tell the player what looking will turn
up?* The probe you already ran falls on the second side — handing over the method
hands over the finding with one step of deniability attached. This is discipline
1's channel audit turned on the ground block itself.

A held expectation has one destination and it is not a prompt: the un-tool, the
move that ends the tool call and addresses the collaborator instead (`AMBIENT.md`
rule 21(a); `.claude/skills/spark-steering/SKILL.md` § *Ask first — the un-tool*).

*(A ceremony spawned four seats over work its own composer had authored. The
composer pre-registered its expected findings, then handed one seat the exact
probe by which it had already obtained one of them; the seat duly found it, and
the audit seat ruled the run's independence unestablishable — the composer "had
already run the probe, saw the result, wrote it down as a prediction, then handed
the probe to the seat." Three seats carried composer-stated facts, and the
composer's own disclosure said "three seats" while naming two. Every artifact this
skill asks for was present — pre-registration held separate, isolated players, an
audit seat — which is exactly why none of them discharges this; the ground blocks
do. The re-run sent seven reviewers whose ground blocks carried the facts and
stated in as many words that no prediction was offered and none was wanted, and
they returned findings the composer had not anticipated, several against the
composer's own work.)*

## The ten disciplines — each paid for by a real failure

1. **Pre-register before the prompts exist.** A forecast that shares bytes with
Expand Down
19 changes: 19 additions & 0 deletions docs/architecture/LLM_HELP_SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -314,3 +314,22 @@ lookup.
- **Field shape is still not validated** (§11), and `llm_help` must not
become the thing that validates it by assuming fields are present.
Render what a descriptor carries; omit what it does not.

## 13. Half A shipped without this surface, and §6 is outstanding (dated entry — July 25, 2026)

`SELF_DESCRIBING_SURFACES.md` §13 records the build. The part that bears on this
spec: `attach_contributions` (`src/rlm/trellis_contribution.py`, called at the
`custom_tools` seam in `trellis_agent.py`) computes the registry × injected-surface
intersection — which §12 above names as the alive catalog's own work — and hands
it to a production model through the per-entry description slot rlms reserves.
`llm_help` itself is still unbuilt, and neither composed-prompt pin moved, because
the slot is filled at run composition rather than in `SYSTEM_PROMPT`.

**§6's drift/gaming half is struck** by a collaborator ruling of July 25, 2026 —
its adversary is whoever writes a descriptor, descriptors are reviewed repository
code, and the experiment reduces to whether a model believes a lie it was told,
which is entailed rather than measured (rule 20). The reasoning is recorded at
`SELF_DESCRIBING_SURFACES.md` §13.1. **§6's discrimination half stands**, as a
paid question under rule 7 that needs a queryable catalog to select within — so
it belongs with `llm_help` and not with a per-tool listing that is always
present entire.
16 changes: 12 additions & 4 deletions docs/architecture/RESPONSE_ARTIFACT.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,18 @@ this record makes.
documents exactly as readily as sixty-four paragraphs, so a model optimising against the budget
**maximises bytes per fetch**. The per-root dedup on `get_ast_blocks` sharpens it: one read of a
document, ever — under-fetching is unrecoverable, over-fetching is free.
- **`ITERATION BUDGET` instructs the opposite of composition.** The kernel tells the worker it has
*"very few REPL turns"*, to combine loading and computing into **one** block, and not to *"spend a
turn on tiny exploratory prints"* — against a `--max-iterations` default of **5**. The doctrine
wants an artifact composed over several turns and multiple slices.
- **`ITERATION BUDGET` instructed the opposite of composition — CLOSED July 25, 2026.** The kernel
told the worker it had *"very few REPL turns"*, to combine loading and computing into **one**
block, and not to *"spend a turn on tiny exploratory prints"* — against a `--max-iterations`
default of **5**. The doctrine wants an artifact composed over several turns and multiple slices,
so the combine-into-one-block directive was rule 24's own falsifying act sitting in the kernel
prompt. Those bytes are gone: the instruction now routes the same scarcity premise to the opposite
conclusion — each turn carries a step, reads the slices that step needs, and the answer comes
together across turns rather than inside any one of them. Both composed-prompt sha256 pins moved
wittingly, together, and were seen failing before they were recomputed (rule 19(c)). The warning
against spending a turn on tiny exploratory prints was sound and is preserved. **`FEATURE_LIST`
row 2.6 stays open**: its other half is the schema ceiling of 9, which is a bound rather than an
instruction, and row 2.7's exhaustion defect gates widening it.
- **No retrieval surface over the corpus has a `locate`.** `get_ast_blocks(root)` returns every block
of a document with full text and no way to ask for a range. The editing half of the runtime has
`load` (shape only), `locate` (addresses plus previews, capped) and a 200-line slice cap; **the
Expand Down
5 changes: 4 additions & 1 deletion docs/architecture/RLM_HARNESS_SCAFFOLDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,10 @@ teaches `verify`, and `trellis_upsum` joins the TOOLS manifest as item 5.
Authored under the prompt-engineering and hypershot-protocol skills
(Guardrail 15). Both composed-prompt sha256 pins moved wittingly and were
recomputed in the same commit (Guardrail 9): default
`ee5bfca6…1200`, omit-arm `322cbe5d…45ae`.
`ee5bfca6…1200`, omit-arm `322cbe5d…45ae` — the values **as of that pass**,
superseded July 25, 2026 when the rule-24 turn-composition fix moved both arms
again. The live pair is always the pair in `scripts/test_modules.py`; digests
quoted in this record are history, never the current value.

### 8.5 What this section produced beyond the three fixes

Expand Down
123 changes: 121 additions & 2 deletions docs/architecture/SELF_DESCRIBING_SURFACES.md
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,9 @@ guard-derivation but the same rule at the other end of the axis.

### 9.2 Honest scope — what ratification does not claim

- **Guard-derivation is specified, not demonstrated.** No shipped surface
- **Guard-derivation is specified, not demonstrated.** *(Superseded July 25,
2026 — §13. This sentence was already false when written: `composeJudgePrompt`
derives from the taxonomy its own parser refuses against.)* No shipped surface
derives its self-description from its guard predicates today. The closest
live thing is `build_textedit_addendum(textedit)`
(`src/rlm/trellis_textedit.py`), and read precisely it *selects* between two
Expand Down Expand Up @@ -615,4 +617,121 @@ surface would make an instance into law by accident (rule 17). It belongs
with `llm_help`'s frame. The banner-qualifier tension (§10, finding 4) and
guard-class granularity (finding 5) stand as recorded; eight surfaces still
carry no descriptor, which the diagnostic now reports rather than leaving
to memory.
to memory. *(That count is superseded — see §13: 8 of 9 are described.)*

## 13. The description slot, and the gate this did not run (dated entry — July 25, 2026)

Half A reached a model. Not through `llm_help`, which is still unbuilt, but
through a slot rlms already reserved and Trellis had never filled: every
`custom_tools` entry renders as one line in the base prompt, `parse_tool_entry`
accepts `{"tool": …, "description": …}`, and the listing splices in at character
1,335 of the 2,116-character protocol prompt — ahead of every Trellis directive.
Trellis passed bare values, so each injected surface rendered as its type name.

**This supersedes two claims above.** §12's closing sentence — *eight surfaces
still carry no descriptor* — is false: `npm run check:surfaces` reports **8 of 9
described**, and the ninth, `UPSUM_BUDGET`, is a bare int declined on purpose
rather than a gap. §9.2's first bullet — *No shipped surface derives its
self-description from its guard predicates today* — was already false when
written, and is further false now: `composeJudgePrompt`
(`src/core/graph/judge_intake_prompt.ts`) renders the same `taxonomy` object
`parseJudgeVerdict` refuses against, with `buildSpawnRequest` re-rendering and
re-hashing before transport, and it predates increment 1 in a different
subsystem and a different language.

**What the frame owns.** `src/rlm/trellis_contribution.py` composes a surface's
line from its registered descriptor and its derived expectations, joins pieces
with the empty string so the frame contributes no prose of its own, and refuses
a brace, a newline, an empty line, boundary whitespace, and a whole composition
over `CONTRIBUTION_BUDGET`. That budget is §5 of `HARNESS_SELF_MODEL.md` paid:
a bound that raises rather than one held by authorial discipline. It is drilled
by `npm run test:contribution`, whose `--negative-control` detects eleven plants
and exits 3.

**The ladder, and which rung a number names.** Three claims, and the earlier ones
do not establish the later:

| rung | property | count today |
|---|---|---|
| registered | the surface carries a descriptor | 8 of 9 injected |
| contributing | that descriptor carries a `contributes` list | 13 |
| wired | a run passes it to `compose_contributions` | 8, plus 5 the static read cannot settle |

*(Figures corrected July 25, 2026 — this table first read 5 contributing and 2
wired, which was the state when the rung split was written and not the state it
shipped in.)*

**The ladder is flat now, and it is flat structurally rather than by
bookkeeping.** The composing call draws its roster from `custom_tools` itself,
so every surface a run injects is wired and no per-surface wiring decision
exists to forget. The five it cannot settle are the staged helpers, injected
conditionally, which the report names rather than counts — unestablished is not
established (rule 15).

`check:surfaces` reports all three rungs, and `scripts/test_surfaces.py` holds
the property that matters: **no surface carries a line the composing call
leaves out.** That check was run against the real historical seam from
`34538be^` and went red naming eleven surfaces, while the two rungs above it
stayed green — which is the failure it exists to catch, the cheap rungs reading
as progress while eleven finished lines reached no model. Its predecessor
asserted that the ladder *narrows*, which turned an unfinished wiring into a
pinned property; that assertion is retired.

**The gate this did not run, stated as outstanding rather than declined
silently.** `attach_contributions` computes the registry × `custom_tools`
intersection, which `LLM_HELP_SPEC.md` §12 defines as the alive catalog, and
hands it to a production model. §6's self-play validation gate — discrimination,
and drift resistance with *selected-on-a-lie* as the pre-committed falsifier —
binds before anything relies on that catalog, and it did not run.

The judgment made instead, so a later session can overturn it rather than
inherit it unstated: the gate's concern is barely engaged at two wired surfaces.
`whenToUse` — the field the *selected-on-a-lie* cell targets — is deliberately
absent from both wired lines, both of which carry guard-derived bounds rather
than intent claims, and a discrimination test over two surfaces measures
nothing. **The trigger is therefore stated rather than the gate waived: §6 binds
before `whenToUse` reaches any composed line, and before any queryable catalog
surface lands.** Either event, and the gate runs first.

**Reachability is unchanged.** `src/repl_sandbox/` still has no non-test caller;
`FEATURE_LIST.md` row 2.4 stands. Nothing here measures whether a model behaves
differently for reading any of it — that remains the separately gated paid probe
of `HARNESS_SELF_MODEL.md` §12.2, and rule 20 still bars running it as a
new-versus-null arm.

### 13.1 The drift half of §6 is struck (collaborator ruling — July 25, 2026)

§13 above stated a trigger: *§6 binds before `whenToUse` reaches any composed
line*. `whenToUse` now reaches three composed lines, so that trigger has fired
— and the collaborator (Matt) ruled the test it points at is not a legitimate
target. Recorded here in his terms rather than paraphrased into agreement.

**The ruling.** `LLM_HELP_SPEC.md` §6's second test asks whether a *lying*
descriptor — a `whenToUse` that oversells — can mislead the model, with
*selected-on-a-lie* as the pre-committed falsifier. Matt: *"If someone wants to
reverse-engineer Trellis to do something pointlessly nefarious with the internal
metaprompts, like lying to the interior model, there is nothing that will stop
that. Not ever."* And: *"We know what happens if you give a language model the
wrong context. It's not a mystery."*

**Why the test cannot inform.** Its adversary is whoever writes a descriptor,
and descriptors are repository code authored under rule 16 and reviewed. So the
adversary is a reviewer, the threat crosses no boundary, and the experiment
reduces to *if we commit a lie, does the model believe it* — whose answer is
entailed by what a language model is. That is rule 20's own failure: an
outcome fixed by construction, reached for because the comparison was closer to
hand than a target. The measurement would report the design.

**What this strikes, and what it leaves.** The drift/gaming half of §6 is
struck, and with it the `whenToUse` trigger §13 stated, which was scoped to it.
§6's **discrimination** half is untouched and stands on its own merits — given a
task and a queryable catalog, does an agent select the right surface — but it
needs a catalog to select *within* and a live model to select, so it is a paid
question under rule 7 and belongs with `llm_help`, not with a per-tool listing
that is always present entire.

**What still binds.** Nothing here weakens the guard-derivation of §3.3, which
was never a test — it is the structural reason an `expects` line cannot drift
from the predicate that refuses, and it holds whether or not anyone probes it.
The descriptor drills hold the same property by construction: a guard-owned
phrase restated in an editorial field is refused by the drills, not by a study.
Loading
Loading