Eureka eureka-substrate cut leaf-key-bound. Soul verdict
eureka-substrate:verdict:cut-leaf-key-bound.s1 holds. Subject locals stay
at 64; resolution locals are bounded at 111 (derived); ids parse by kind;
Sha::names_same_commit. Every stored key re-derives byte for byte.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The previous commit (34099183) does not pass its own tests: two of them
built a wide local as one label, which is itself bounded at 64. This commit
builds them as dotted parts. The commit before it builds; two of its tests
fail.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
LOCAL_MAX (one 64-byte bound for every kind) is deleted. Subject locals stay
at SUBJECT_LOCAL_MAX = 64, so no stored key moves. A resolution's local gets
RESOLUTION_LOCAL_MAX = 111, derived from the subject bound and the kind names
(a depth-two chain over a maximal subject at u32::MAX sequences), with a const
assert that an id still fits a Short. local_max(kind) is the one place the
bound is chosen; pipeline_key's composer and pipeline_id's parser both read
it, so every key pipeline_key derives is an id pipeline_id accepts.
Sha::names_same_commit: one spelling is a prefix of the other.
Tests: every_resolvable_kind_resolves_two_deep, the resolution side of the
whole-local bound, parser bound by kind, sha_names_same_commit, and the
#[ignore]d stored_documents_read_back over a real mind snapshot
(HUGINN_MIND_SNAPSHOT). The old depth-arithmetic test body is replaced.
Build status is shown by the verify run that follows. Operator ruling eureka-substrate:ruling:key-bound (per-kind).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Lands the live Eureka pipeline branch on main per operator ruling
eureka-substrate:ruling:merge-to-main-first ("Merge to main first"),
cut spec eureka-substrate:cut_spec:cut-merge-epiphany-main.r1.
The merged tree equals the branch tip's tree (a75aa388); the branch is
kept and receives no further commits.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Huginn moves to CultLib 8fc74c7 for the RUDP client bind fix, and the
pipeline leaf's CultCache types cross Huginn's API, so the leaf moves with
it. cultcache-rs changes between the revs are reader-side only: named
refusals for variant stores; the v1 formats read as before.
The lock also takes the Ghostlight pin that epiphany-core/Cargo.toml
already named (22937b71); the lock still carried 22281891.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One move of epiphany-pipeline's cultcache-rs, a0813c6 -> 6251cbc, so Huginn can
hold one cultcache-rs. cultcache-rs content is unchanged across the range;
the leaf suite is unchanged at 38. Cargo.lock gains the second cultcache-rs
entry the workspace now carries.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Q-H1 B: wait for Idunn, no interim unit. Q-H2 C: no backup yet.
Q-H4: one mind, eureka, plus session attribution on receipts.
Q-H5: park Cut 12. Q-H6 A: the hybrid, with the direction that
remaining prose keeps moving into typed state.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
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>