Imagination (Opus) remapped Cuts 11-15 against Huginn 8c5f784, with the
read-side and body-plane cuts landing ahead of them. Cut 11 splits into
11a/11b and Cut 13 into 13a/13b. Cut 12 is proposed for parking. Five
operator questions are open (Q-H1, Q-H2, Q-H4, Q-H5, Q-H6).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both headers still said "none started" and listed operator questions
as open. Q-RS1/Q-RS2 and Q-BP1/Q-BP2 were ruled on 2026-09-22, RS-L,
RS-2 and RS-1 closed that day, and selection Cut 1 merged at dbee044.
BP-1 is in Hands, with two overrides to the spec: no committed mutation
entries, and verification on Yggdrasil.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Follows the source cut: the OrgRepo doc comment (RS-L closing fix 2) now
publishes only the grammar, the 140-byte bound and the case-insensitive
identity, with the bounded_text!/hand-written-impl reasoning moved to a
source comment. Regenerated with cargo test's own derivation so the
byte-for-byte pin (pipeline_published_schemas_match_derivation) stays green:
campaign, cut_report, cut_spec, finding, follow_up, hand_off, ruling and
stewardship all embed OrgRepo (directly or through ForeignRef's repo field).
instance, question, resolution, target and verdict do not reference OrgRepo
and are unchanged.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Soul's third RS-L pass ruled the leaf's five promises hold but found four
closing items (soul-e20-notes.md, 2026-09-22):
1. Every OrgRepo Eq/Hash/Ord/PartialOrd assertion compared values that
should already be equal, so eq -> true, hash -> (), cmp -> Equal,
partial_cmp -> None and partial_cmp -> self.0.partial_cmp(&other.0) all
survived as mutants. Add the unequal direction (assert_ne! on two
different repos, differing hashes, a non-Equal ordering) and std's
partial_cmp(a,b) == Some(cmp(a,b)) contract for both an equal and an
unequal pair.
2. The published OrgRepo schema description carried ~1,100 characters of
Rust-macro justification into nine contracts. Split the doc comment: the
grammar, the 140-byte bound and the case-insensitive identity stay in the
published /// doc comment; the bounded_text! delegation reasoning moves to
a plain // source comment, so it stops reaching schemars.
3. lib.rs said "eleven bidi control code points" above twelve fixtures
(ALM, LRM, RLM, LRE, RLE, PDF, LRO, RLO, LRI, RLI, FSI, PDI). Say twelve.
4. campaign.repos admitted both spellings of one repository. Add
PipelineRefusal::DuplicateRepo and a campaign-only validation hook
(value_types!'s new optional `=> extra` clause) that refuses two entries
sharing an OrgRepo identity; distinct repos still validate.
This commit is the source half; the nine published schemas are regenerated
in the next commit to match fix 2.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
OrgRepo's doc comment now explains its hand-written identity-based
PartialEq/Eq/Hash/PartialOrd/Ord and the ASCII-case-insensitive .git
refusal (S-1, S-2); Title's regains the bytes-versus-characters caveat
(S-5). Both are schema descriptions, so nine of the thirteen published
schemas move: campaign, question, ruling and cut_spec carry Title;
campaign, cut_report, cut_spec, finding, follow_up, hand_off, ruling and
stewardship carry OrgRepo directly or through ForeignRef. Byte-for-byte
identical to what `schemars::schema_for!` derives from the code in the
previous commit, pinned by pipeline_published_schemas_match_derivation.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
case-insensitive, the bidi set is pinned per-point, and the title rule
refuses two more separators
Soul's RS-L second-fix pass found identity() exposed but never adopted:
key derivation and every derived PartialEq/Ord/Hash still ran on the raw
string, so GameCult/Epiphany and gamecult/epiphany were two stewardships
and two store keys (S-1). The .git refusal was case-sensitive, so a case
variant reached an identity() the validator itself refused (S-2). Only
U+202E was pinned in the bidi match arm; every other code point's test
fixture was a lone character the alphanumeric rule already refused, so
cargo-mutants could not see a class-member deletion (S-3). is_control()
is Cc only, so U+2028/U+2029 (Zl/Zp) slipped through the widened title
rule and a one-line field could carry a hard line break (S-4). The Title
schema description lost the bytes-versus-characters caveat the original
RS-L cut carried (S-5).
- S-1: `OrgRepo` is pulled out of the `bounded_text!` macro (which has no
per-member override) and given hand-written PartialEq, Eq, Hash,
PartialOrd and Ord, all defined over identity(). Every other
`bounded_text!` member keeps the macro's derives untouched. Key
derivation for Stewardship and HandOff (lib.rs's Stewardship/HandOff
arms of pipeline_key) now escapes repo.identity() instead of the raw
string.
- S-2: org_repo_text's `.git` suffix check is ASCII-case-insensitive.
identity() stays valid for every value validate_org_repo accepts,
since lowercasing never changes the outcome of any rule in the
grammar.
- S-3: title_text's control check also refuses U+2028 and U+2029
alongside is_control(); everything else, including ZWJ/ZWNJ, is
unaffected.
- S-5: Title's doc comment (the schema description) regains "enforced by
admission; JSON Schema length counts characters".
Tests add: OrgRepo equality/ordering by identity, a HashMap and a
BTreeMap each keyed by both spellings holding one entry, identity()
always itself valid, case-insensitive .git fixtures (a/b.GIT, a/.GIT,
A/B.GIT), one Stewardship store key for both spellings, all eleven bidi
code points pinned with embedded (`a<cp>b`) fixtures instead of lone
characters, and U+2028/U+2029 refused embedded.
Schemas regenerated in the next commit.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Derived on Yggdrasil from the rewritten lib.rs by running
pipeline_published_schemas_match_derivation, which writes every stale
derivation to a temp directory on failure; those nine files are copied back
here byte for byte. Re-running the test afterward passes clean (0 stale).
Nine of the thirteen published kinds change: campaign, question, ruling and
cut_spec carry Title's new description; cut_report, finding, follow_up,
stewardship and hand_off carry OrgRepo's new description and its maxLength
move from 200 to 140. instance, resolution, target and verdict reference
neither type and are untouched.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
refuses .git and gains identity()
Soul's F2 finding on the second RS-L pass: a 1-byte title, " ", "\0", "\n",
U+200B and U+FEFF all passed as "non-empty" under the whitespace-plus-hand-
written-denylist check, because that check tested is_whitespace() rather
than the actual grammar rule (F2) or "not a bare placeholder" (F1/F3).
title_text is rewritten to the three-rule grammar Self ruled: at least one
char::is_alphanumeric() character, no char::is_control() character, and no
bidi control character (U+061C, U+200E, U+200F, U+202A-U+202E,
U+2066-U+2069). The hand-written C0/C1 ranges and the zero-width/BOM
denylist are deleted outright, not narrowed -- a character not covered by
one of the three tests is allowed, which is the point: no more enumerated
exception list to keep in sync with Unicode.
Discrepancy from the fix spec: the spec's refused-case list names "U+3164
alone" (HANGUL FILLER). Unicode gives it General_Category Lo, so
char::is_alphanumeric() is true for it on this toolchain (confirmed by a
failing assertion on Yggdrasil before the test was corrected). Reintroducing
a denylist entry for one code point to force that single case would
contradict the "delete the denylist" instruction this same fix batch
carries, so the test now pins U+3164 alone as accepted and documents why
inline.
OrgRepo (F7's GitHub grammar, unchanged in shape) gains two things:
- a repo name ending in ".git" is refused (GitHub strips it, so a document
that carried it would silently alias another stored repo);
- OrgRepo::identity() is the one canonical key, ASCII-lowercased, with a doc
comment saying every comparison and lookup goes through it. Huginn adopts
it at BP-2 (out of scope here).
The dead `!repo.contains('/')` check is deleted: the repo byte alphabet
already excludes '/', so a second slash was always refused by the byte
check, never by that clause.
Consecutive hyphens stay allowed (GitHub's own signup rule is stricter than
its stored-repo grammar; the ruling this leaf implements is silent on
consecutive hyphens, so nothing here narrows it).
OrgRepo's published maxLength moves from 200 to 140 (39 + 1 + 100, the true
grammar maximum); the Title and OrgRepo doc comments now state the rule and
the true maxima directly and name no private function, since the derived
JSON Schema descriptions come from these comments verbatim.
Tests added/changed in question_and_ruling_carry_a_title and
the_org_repo_and_label_doors_are_the_grammar: the full refused/accepted
title matrix from the fix spec (RLO alone and with text, LRM alone, a lone
combining mark, a variation selector alone, NBSP alone, emoji-only,
Persian text with ZWNJ, a ZWJ pair, "a 🚀", 200 accepted / 201 refused
bytes already pinned); OrgRepo's owner=39/repo=100 accepted boundaries
beside the existing 40/101 refused ones, a/b.git and a/.git refused,
a--b/c--d (consecutive hyphens) accepted, and identity() lowercasing.
Hand probes on Yggdrasil (M0 green, restored): H01-owner-max-38,
H02-owner-min-2, H03-repo-max-99, H04-repo-min-2, H05-repo-no-hyphen,
H05b-repo-no-dot, H05c-repo-no-underscore and H05d-owner-no-hyphen all still
die under the rewrite. H06/H06b (2028/2029), H07/H07b/H07c (C0/C1 ranges),
H08 (zero-width-only), H09/H09b (U+2060/U+FEFF) and H10 (is_whitespace vs
is_ascii_whitespace) no longer apply: the code they mutate no longer exists,
since this fix batch deletes exactly that denylist and that whitespace
check.
cargo test -p epiphany-pipeline --lib: 37/37 on Yggdrasil.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Better to have nothing than a harness that punishes refactoring
(operator ruling, 2026-09-22). Remove all eight tools/*mutations*.psd1
files (921 lines total): cut5, cut6, cut6b, cut6c, cut6d,
cut8-epiphany, cut10-epiphany, readside-leaf. The harness that ran
them, eureka-mutations.ps1, was already deleted from the Eureka skill
(37c80e4).
notes/eureka-body-plane-cut.md, notes/eureka-pipeline-state-cut.md and
notes/eureka-read-side-cut.md still name these suites; they are Self's
campaign records and are left untouched.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Epiphany pinned ghostlight-persona-projection at 2228189
(2026-08-16), which still carries the vendor/cultcache-py submodule
pointing at https://github.com/GameCult/cultcache-py.git. That repo
was folded into CultLib's packages/cultcache-py and no longer exists,
so a fresh clone that recursively fetches Ghostlight submodules fails
cargo's `unable to update` step even though Epiphany's own tree is
otherwise clean.
Move the pin to 22937b7 (2026-09-13), the nearest Ghostlight revision
without a dead submodule: it replaces vendor/cultcache-py with the
published cultcache-py PyPI package and keeps only vendor/eve. Between
the two revisions the crate's public surface stayed source-compatible
for the three call sites Epiphany uses, with three additive/field
changes: ProjectorPrompt and PersonaPrompt gained a required
word_budget field (set to 180, matching Ghostlight's own
PERSONA_WORD_BUDGET convention for narrative Persona controllers), and
InterpreterPrompt's output_schema became Option<&str> (wrapped in
Some(..) to keep the always-supplied schema).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Title now refuses a bare placeholder: at least one non-whitespace
character, and no control characters (C0, C1, U+2028/9, the zero-width
characters, or the BOM). The 1-to-200-byte bound is unchanged, and the
Title schema now carries a truthful minLength/description pair instead
of the old ruling-history prose (F2, F3, F4).
OrgRepo now follows GitHub's own owner/repo grammar: an owner of
[A-Za-z0-9-], 1-39 bytes, no leading or trailing hyphen; a repo of
[A-Za-z0-9._-], 1-100 bytes, never "." or ".." (F7). Two fixtures used
an OrgRepo the new grammar refuses (a dotted owner, an underscored
owner); both are rewritten to carry the same character on the repo
side of the slash, which the grammar still allows, with their expected
keys recomputed.
Regenerated the four published schemas (campaign, cut_spec, question,
ruling) that reference Title, pinned by the byte-for-byte derivation
test.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Q-RS1 ruled B: a new bounded text type, Title (1-200 bytes, never empty),
replaces Short on all four leaf titles -- campaign, cut spec, and the two
new fields on question and ruling. The epoch moves anyway in this cut, so
tightening the two existing titles now avoids a second epoch bump later
just to make a title required.
PIPELINE_SCHEMA_EPOCH and all thirteen type ids move to .v2. The thirteen
schema files are renamed and regenerated, and index.json/README.md follow.
Two public doors join Slug::validate_slug on the same pattern:
OrgRepo::validate_org_repo and Label::validate_label, each delegating to
the grammar its own document field is already held to. RS-3 will read the
organ's repo and cut aliases through these.
Tests: the_org_repo_and_label_doors_are_the_grammar and
question_and_ruling_carry_a_title (37 total, up from 35). Mutation suite
tools/eureka-readside-leaf-mutations.psd1 (L1/L1L, L2/L2L, L3/L3L) verified
killed against M0.
No other consumer in this workspace depends on epiphany-pipeline as a
Cargo dependency; epiphany-core's runtime_spine stand-in hardcodes a
pipeline-shaped type id deliberately (RS-L's negative grep excludes it) and
is unaffected since its test only checks the "epiphany.pipeline." prefix.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The leaf's own door test, slug_validate_applies_the_dotted_grammar, checked
the grammar but never pinned the 64-byte bound on the whole name, the
64-byte bound on a lone label, or NUL as a refused label byte. Extends it
with a two-label 64/65-byte pair (each label far under 64, so only the
whole-name check can be the one refusing 65), a direct Label check at
64/65 bytes (no whole-name wrapper to interfere), and a NUL case. Adds
three matching mutation entries to tools/eureka-cut10-epiphany-mutations.psd1
that drop each check in turn; all three die under the extended test.
The suite's own header still named the deleted repo-local harness path.
Corrected to the Eureka skill's copy, GameCult/Eureka.
Verified: cargo test -p epiphany-pipeline --lib, 35/35. Full mutation
suite through the Eureka harness: 5/5 killed (G1, G1L, S5whole, S5label,
S5nul), M0 green.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Slug::validate_slug applies the crate's own dotted_text grammar, the
same check every Slug field is held to, following PipelineRef::validate_ref's
pattern. Named validate_slug rather than validate so it does not shadow
Bounded::validate for in-crate callers.
Adds a leaf test covering one valid dotted name and refusals for fullwidth
characters, .., both path separators, the empty string, and an empty label.
Self's ruling on the F6 fork, 2026-09-22: fill the gap in its owner rather
than leaving Huginn's PipelineInstance wrapper beside it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Imagination's map (Opus), placed by Self. BP-1 gives cultnet-rs the reference's
content-plane chunk messages; BP-2 moves the pins together; BP-3 makes the
daemon defer an oversize answer instead of refusing it. Q-BP1 (which physical
path) and Q-BP2 (what the summary is) are open for the operator. BP-1 waits on
selection Cut 1's Rust commit, because both edit cultnet-rs contracts.rs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
It lived here because this repo needed it first, and the memory organ had been
reaching across a boundary for it. It takes the repository as a parameter, so
one copy serves every campaign and a fix to it fixes all of them.
Every earlier reference here to the Epiphany path is history and no longer
resolves.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The paragraph explaining why that dispatch arm could not be pinned is deleted
from the code and from the entries header, because it was wrong, and the probe
that disproved it is now a committed test. The size gate is pinned on its
boundary rather than near it, and an instance name that differs only in case
stands beside the ones that differ in length and prefix.
All six new entries survived the shipped suite before this batch, so none of
them is a mutant that could never have failed. The entry count recorded here
was wrong and is corrected from the file itself.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A body the control plane cannot carry travels the transfer that exists for
exactly that, and the control plane carries the summary and a reference to it.
Raising the window only moves a number we would keep revising, and bounding
documents smaller argues with what a cut spec honestly is.
The refusal stays as the backstop. A caller that cannot be given an answer is
told so by name rather than left listening to silence.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The measurements hold under an independent probe and the transport itself
agrees, so the document that cannot be read back is a fact rather than an
inference. The gate refuses exactly where the transport gives up, and the
refusal is small enough to always arrive.
The arm reported as impossible to mutate was not. A probe built from the
crate's public surface kills both mutants, and it gets committed, because a
kill that lives in an agent's scratchpad is not evidence anyone can rerun.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A receipt now records where it falls in the order, so a page is a position
rather than a guess, and the store takes the version that costs nothing today.
The two hardcoded endpoints go rather than surviving as presets of the thing
that replaced them. The leaf gains titles, because a catalog row showing only
an identifier is not a catalog, and it rides the same version bump instead of
asking for a second one.
The vocabulary itself is not ours: it fills the hole in CultNet, and the organ
becomes a consumer of it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
An answer too large to send is now refused by name instead of vanishing, and
the three rules that were pinned by fixture luck are pinned by fixtures that
resemble each other. Measuring the refusal turned the size question into a
different one: a cut spec at the leaf's own bounds does not fit, so admission
accepts a document this door can never return. That is an asymmetry rather
than a limit and it goes to the operator.
One mutation entry was refused rather than faked, and the reason is written
where the next reader will find it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
An Eyes pass established what already exists for a typed query surface, inside
the substrate first and in published work second, with an evidence pointer for
every claim. It found no reusable shape in our own runtimes, three flat option
structs invented independently because no general one exists, and a citation
hop query we built and deleted with its host surface rather than on its merits.
It lands in the repository because a facts file that lives only in a scratchpad
is the same failure as a harness that lives only in a scratchpad, which this
campaign has now paid for twice.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The organ answers typed refusals over the wire and holds no rule beside the
mind, which is what the cut was for. It also loses any answer too large for
the window, without a word to the caller, and the spec's idea of document size
was never the leaf's. A response that will not fit is now refused by name,
carrying its size and the limit, and the window rises to the worst case a
single document can reach. No truncation, no pagination the caller did not
ask for.
Three rules turned out pinned by luck rather than by tests, among them the
instance check, whose mutants survived because no fixture pair had ever shared
a length.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The organ answers over the hub, the daemon holds no rule of its own, and the
instance check has one owner. Every discrepancy this cut hit was the map's
rather than the Body's, including a constant that does not exist in CultLib
and a mutant that could not fail because the thing it broke released the port
on its way out.
Several loosening mutations the brief required turned out unfalsifiable and
were replaced. That replacement is the first thing Soul is told to attack: a
loosening swapped for an easier target is a hole wearing a green tick.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Epiphany's stake in the campaign closed with the leaf owning the schemas and
nothing else. The record keeps the scars: a store deleted whole after the
operator rejected it, a grammar redesigned on its third patch, a fix that
introduced a replay regression, a harness that ate the work it was testing,
and the five corrections the operator had to make to the agents' model.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
One door now opens onto the reference grammar, and both read doors refuse a
ref that is no ref before answering over it. The leaf owns the shape of an
id; per-kind local shape stays with admission, where the sequence rules
already live, and a resolution's key is derived rather than written, so
nothing malformed reaches the write path. The status header is rewritten to
what has actually landed.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>