Getting it into your agent
One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.
npx agentmods add skills/jongwony/epistemic-protocols/boundnpx skills add jongwony/epistemic-protocols --skill boundgit clone --depth 1 https://github.com/jongwony/epistemic-protocolsWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/skills/jongwony/epistemic-protocols/bound)<a href="https://agentmods.dev/skills/jongwony/epistemic-protocols/bound"><img src="https://agentmods.dev/badge/skills/jongwony/epistemic-protocols/bound.svg" alt="Measured on agentmods" height="20"></a>What it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5 | $0.00041 | $0.16097 |
| Opus 5 | $0.00020 | $0.08049 |
| Sonnet 5 | $0.00008 | $0.03219 |
| Haiku 4.5 | $0.00004 | $0.01610 |
Grade A, and why
bound scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured today.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Nothing flagged
None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.
How it starts
The opening of the file, as written. The whole thing — 360 lines — stays where its author put it; the contents beside it link to each section on GitHub.
Horismos Protocol
Define epistemic boundaries per decision through AI-guided classification. Type: (BoundaryUndefined, AI, DEFINE, TaskScope) → DefinedBoundary.
Definition
Horismos (ὁρισμός): A dialogical act of proactively defining epistemic boundaries per decision, where AI probes for boundary-undefined domains, dispatches the boundary kind up-front (a KindRouteMap of recognition seeds — direction/priority, scope, type/concept, ownership — plus an emergent/naming path) through a fail-closed deficit-fit certificate, collects contextual evidence to enrich classification quality, and presents each domain for user classification by a uniform settlement disposition (user-supplies / AI-proposes / AI-autonomous / dismiss) into a BoundaryMap consumed by all downstream protocols. The disposition coproduct is the same for every kind — the captured kind sets WHAT boundary is being settled, the disposition sets HOW that boundary value is settled downstream. Ownership is one kind among the seeds (who decides), and it is the degenerate case where the boundary value being settled is itself the disposition — so for ownership, content and disposition coincide; for every other kind they separate cleanly.
── FLOW ──
Horismos(T, B_prior?) → Probe(T) → Bᵢ? →
|Bᵢ| = 0: Qc(zero_signal_finding) → Stop → [Confirm: deactivate | Reopen(d): Bᵢ := {d}, proceed] -- zero-signal gate (`Zero-signal surfacing`)
|Bᵢ| > 0: Phase 0b sync_kind_route(T) → KindRouteMap → -- up-front KIND dispatch (dispatch-first: kind settles before downstream consumers read it)
[single_dominant_kind(KindRouteMap, T, context): relay(captured_kind + basis) (extension) → proceed (kind committed) -- entropy→0 fast-path (option-set relay test): one kind dominates, foils route away → NO turn yield
| else: Stop → captured_kind (constitution)] -- ≥2 viable hypotheses ∨ undecidable foil ∨ emergent gesture naming no single kind ∨ live ground leaves the emergent question undetermined → mandatory Constitution gate
bind_kind(captured_kind) → KindBinding -- {label, positive_predicate, evidence, atomicity}; non-atomic → split/route, re-sync before continuing
certify(KindBinding, local_claims) → DeficitFitCertificate -- fail-closed: status(certificate) ≠ pass BLOCKS value-space binding (split / route claim / narrow-disambiguation first)
status(certificate) = route: → route_away(routed_deficit) → deactivate (a local route claim holds the kind; no DefinedBoundary)
KindBinding.atomicity = non-atomic: → split → re-sync Phase 0b → re-certify
status(certificate) = ambiguous: → Qa(captured_kind, claims_supported) → Stop → Attribution → attribute — Own: status re-reads as pass → bind_value_space; Route(d): route_away(d) → deactivate; Unattributable: deactivate (unattributable) with a relay of the finding; no DefinedBoundary
status(certificate) = pass: → bind_value_space → BoundaryClassification -- the uniform settlement-disposition coproduct, generated ONLY after certificate passes (same codomain for every kind; captured kind sets each option's content, not the coproduct)
init_loop_state: cycle_n=1, BoundaryEssence="", B = seed_if_kind_match(B_prior, captured_kind), B_seed = Bᵢ (seed only when kind(B_prior) = captured_kind; kind-mismatched prior map → advisory, NOT seeded — see seed_if_kind_match; B_seed carries the Phase 0 domain signal — incl. the zero-signal Reopen(d) seed {d} — as unclassified cycle-1 anchor candidates (non-anchored remainder residualizes at the Phase 1 residualize), never unioned into the classified map B), default=DefaultClassification(MixedTrend), EssenceTrend(history, cycle_n)=MixedTrend at init since cycle_n < 2 (kind-general — the per-cycle disposition-trend machinery runs for every kind), loop:
Phase 1 Ctx(T, cycle_n) [per-cycle re-scan] → (Sub-D[cycle_n], auto_resolved?) →
Sub-D empty ∧ residual ≠ ∅: → Phase 4 (substrate exhausted, residual remains)
Sub-D empty ∧ residual = ∅: → TERMINAL CARRIERS (Phase 1 row) → DefinedBoundary → converge (substrate exhausted, all surfaced domains classified — no empty Phase 4 gate)
auto_resolved: → Phase 3 (skip Phase 2 for this cycle; no user A — the substrate-settled classification is carried into Phase 3)
else: → Phase 2
Phase 2 Qc(Sub-D[cycle_n], kind, BoundaryClassification, BoundaryEssence, cycle_n, B_snapshot, default) → Stop → A
Phase 3 (user-response: conservative parse(A) → (typed_A?, TerminationIntent?) — a commitment is recognized only when the whole response's decision-relevant meaning supports that reading; otherwise Phase 2 re-presents from A with the map unmutated; auto-resolved: typed_A = substrate-settled classification, no TerminationIntent) →
integrate(typed_A?, B, BoundaryEssence) → (B', Δessence) -- total current-cycle fold: classification updates the anchor; termination-only residualizes it and returns B' = B with the empty delta
crystallize(Δessence, BoundaryEssence) → BoundaryEssence' -- sole producer of the accumulated essence; the empty delta is the identity
refresh B'-snapshot with the current default_for_residual -- BEFORE the branch below, on EVERY fold including a terminating one: a just-residualized anchor gets its provisional entry here, so every route below reads a complete map
ImplicitTermination: → TERMINAL CARRIERS (Phase 3 row) → DefinedBoundary → converge
-- "default" is Λ.default_for_residual at entry to Phase 3 (the value Phase 2 surfaced); NOT re-derived
ExplicitTermination: → Phase 4
else: → DefaultClassification(EssenceTrend(history', cycle_n)) → default' for NEXT cycle (kind-general; count-only over the uniform disposition) → re-snapshot with default' → cycle_n += 1, loop
Phase 4 (optional path) Qf(residual, FinalGateDisposition) → Stop → TERMINAL CARRIERS (Phase 4 row) → DefinedBoundary
── MORPHISM ──
TaskScope, B_prior?
→ probe(task, context) -- detect boundary-undefined domains
→ sync_kind_route(task, context) → KindRouteMap -- up-front dispatch: one hypothesis for every recognition seed (direction/priority, scope, type/concept, ownership) + emergent/naming path; each seed hypothesis carries positive_predicate, evidence, differential_future, route_away conditions
→ [single_dominant_kind: relay(captured_kind) (extension) | else: present(KindRouteMap) (constitution)] -- option-set relay test over the kind hypotheses AND the live ground: one dominant kind (entropy→0) relays without a turn yield — either a seed (positive_predicate satisfied, foils' route_away hold, no emergent indicated) or an emergent kind the user's own wording already names unambiguously; ≥2 viable ∨ undecidable foil ∨ an emergent gesture naming no single kind ∨ an emergent question the live ground leaves undetermined gates. BOTH branches feed bind_kind → certify → bind_value_space (certificate fail-closed on both)
→ bind_kind(captured_kind) → KindBinding -- {label, positive_predicate, evidence, atomicity}; non-atomic kind → split or route before continuing
→ certify(KindBinding, local_claims) → DeficitFitCertificate -- {own_claim, route_claims[], claimed_by, evidence}; fail-closed — status(certificate) ≠ pass BLOCKS bind_value_space; fits the captured kind's positive_predicate against the own claim and the route claims inscribed in THIS SKILL.md
→ bind_value_space → BoundaryClassification -- the uniform settlement disposition {UserSupplies, AIPropose, AIAutonomous, Dismiss}, generated ONLY after certificate passes; same codomain for every kind (kind sets each option's content); relay / dead-signal test applied; frozen for the activation
→ seed(B_prior, B) -- hermeneutic carry-over at Phase 0b step 4 (AFTER bind_value_space + B init): optional prior BoundaryMap seeds the freshly-initialized B ONLY when kind(B_prior) = captured_kind (same-kind — its dispositions were settled over the SAME boundary question). Values are always type-compatible now (every kind shares BoundaryClassification), so the guard is SEMANTIC: a kind-mismatched prior answers a DIFFERENT boundary question (e.g. an ownership prior's "AIAutonomous" decided who-owns, not how-wide a scope is) and is surfaced as advisory context, NOT seeded. Seeded domains enter `context_resolved` partition with "prior classification" basis (entries mutable in subsequent cycles). Phase 0 only DETECTS B_prior (binds Λ.B_prior together with its kind); it does not seed B, which does not exist until loop-state init
→ enrich(domains, codebase, cycle_n) -- per-cycle context collection (re-scan)
→ classify(domain, as_inquiry) → typed_A ∈ BoundaryClassification -- per-cycle object_ref(kind) classification by the uniform settlement disposition (the captured kind sets the content of each disposition option; the 4-value coproduct itself is kind-invariant)
→ integrate(typed_A?, B, BoundaryEssence) → (B', Δessence) -- total current-cycle fold; does NOT update default_for_residual
→ crystallize(Δessence, BoundaryEssence) → BoundaryEssence' -- sole producer of the accumulated essence; the empty delta is the identity
→ snapshot(B', residual, default_for_residual) → B_complete' -- refreshed after EVERY fold, termination included, and BEFORE any terminal route below: this is what gives a just-residualized anchor its provisional entry — classified entries ∪ (residual ↦ default_for_residual), at the value Phase 2 surfaced
→ DefaultClassification(EssenceTrend(history', cycle_n)) → default' -- count-based EssenceTrend → DefaultClassification for NEXT cycle's residual (runs on loop continuation ONLY; count-only over the uniform disposition, so the derivation is kind-general — it reads disposition counts, never kind-specific content)
→ snapshot(B', residual, default') → B_complete'' -- continuation only: supersedes B_complete' for the cycle about to open
→ [finalize | bulk_classify | identity] → Λ.boundary_map -- terminal operation selected by the reachable convergence path; source, write, and final value are defined once in TERMINAL CARRIERS
→ DefinedBoundary
requires: boundary_undefined(T) -- runtime checkpoint (Phase 0); sole activation precondition. (status(certificate) = pass is the Phase-0b value-space-BINDING gate, NOT an activation precondition — it lives in the certificate-before-binding invariant below and the Phase 0b → Phase 1 transition; route/ambiguous status routes/re-syncs inside Phase 0b rather than blocking activation.)
deficit: BoundaryUndefined -- activation precondition (Layer 1/2); the certificate's own_claim deficit for in-scope kinds
preserves: task_identity(T) -- task scope invariant; BoundaryMap and BoundaryEssence mutated; B_prior seed entries are mutable across cycles
invariant: Definition over Assumption
invariant: certificate-before-binding -- status(certificate) = pass strictly precedes bind_value_space (shared meta-backbone order)
── TYPES ──
T = TaskScope (task/project requiring boundary definition)
B_prior = Optional(SeededPrior) -- optional invocation seed for hermeneutic carry-over (prior BoundaryMap detected in session context). Seeded into B at Phase 0b step 4 ONLY when the prior map's kind matches the captured kind (same-kind — same boundary question). The guard is SEMANTIC, not type-based: every kind shares BoundaryClassification, so a mismatched prior's values are type-valid but answer a DIFFERENT boundary question, so a kind-mismatched prior map is surfaced as advisory context, NOT seeded as a structural entry. Seed entries are mutable across cycles
SeededPrior = { map: BoundaryMap, kind: Kind } -- the prior BoundaryMap together with the boundary kind it was produced over (Phase 0 step 3 detection binds both). The carried kind is the typed carrier the same-kind guard tests: kind(B_prior) ≡ B_prior.kind
seed_if_kind_match : (Optional(SeededPrior), Kind) → BoundaryMap -- seeds the prior map ONLY when B_prior.kind = captured_kind (returns B_prior.map); a kind-mismatched prior (B_prior.kind ≠ captured_kind) or B_prior = ⊥ returns ∅ (a mismatched prior is surfaced as advisory, not seeded)
Probe = T → Set(Domain) -- boundary-undefined domain detection (Phase 0; existence check, not exhaustive enumeration)
Domain = { name: String, description: String, evidence: Set(Evidence) }
Evidence = { source: String, content: String }
Bᵢ = Set(Domain) from Probe(T) -- initial boundary-undefined domain signal (cycle 1 seed: formally carried into Phase 0b loop-state init as Λ.B_seed = Bᵢ, kept separate from the classified map B until classification — on zero-signal Reopen(d), Bᵢ = {d} is the one entry the Phase 1 re-scan cannot be assumed to re-derive)
ZeroSignalConfirmation = user's answer to a zero-signal finding ∈ {Confirm, Reopen(Domain)} -- Confirm accepts no boundary-undefined signal (`Zero-signal surfacing`); Reopen names a domain Probe(T) missed, seeding it into Bᵢ and proceeding
-- Shared meta-backbone (KIND dispatch). One canonical schema; bound-local instantiation ONLY for object_ref, local_value_space, the label field's type (Kind), the own claim, and the local route claims.
KindRouteMap = sync_kind_route : (T, context) → { hypotheses: List<KindHypothesis>, emergent: NamingPath }
-- up-front dispatch sync surfaced at Phase 0b; hypotheses contains one carrier for every recognition seed (direction/priority, scope, type/concept, ownership), while the emergent/naming path keeps the kind open beyond those priors
KindHypothesis = { label: Kind, positive_predicate: String, evidence: Set(Evidence), differential_future: String, route_away_if: String }
-- each named kind is a PRIOR (recognition seed), NOT a closed coproduct member (`Dynamic rendering`: no fixed taxonomy)
NamingPath = free-response affordance for a kind not among the seeds (emergent capture; user names the kind, or extends/replaces a seed)
single_dominant_kind : (KindRouteMap, T, context) → Bool -- option-set relay test (entropy→0 predicate): true iff the live ground determines EXACTLY ONE kind, by either route — (a) SEED: exactly one hypothesis has its positive_predicate unambiguously satisfied by the framing, every other hypothesis' route_away_if holds, and (T, context) indicates no emergent capture; or (b) EMERGENT: (T, context) names exactly one emergent kind unambiguously, which IS the capture — the naming already happened in the user's own words, so gating it would ask for a value the live ground has settled. The seed conjuncts read KindRouteMap, which carries every recognition seed; the emergent conjunct turns on what the framing DENOTES, so it resolves against (T, context) — the user's own wording and the accumulated context — and the seed summary never stands in for it, because a summary cannot carry a branch whose decision rests on an unresolved denotation. An undecidable route_away_if, an emergent gesture resolving to no single naming, OR an emergent question (T, context) leaves undetermined makes the predicate false. true ⟹ the dispatch sync RELAYS the captured kind without a turn yield (Phase 0b sync_kind_route_relay, extension), citing its basis in the user's own wording — verbatim on route (b), where that wording IS the capture and a paraphrase would substitute the AI's reading for it; false ⟹ the mandatory Constitution gate fires (≥2 viable kind hypotheses, an undecidable foil, an emergent gesture naming no single kind, or an emergent question the live ground leaves undetermined). The captured kind still flows through bind_kind → fail-closed certify → bind_value_space on BOTH branches — the relay collapses only the kind-capture turn yield, NEVER the certificate (a non-pass certificate gets the full gated treatment — route → route_away/deactivate, ambiguous → re-sync the gate)
Kind = captured boundary kind (seed ∈ {direction/priority, scope, type/concept, ownership} | emergent)
-- object_ref(kind) : the anchor the loop classifies (= Domain for bound, every kind; bound-local instantiation point — the kind sets WHAT the Domain's boundary is about, not the anchor type)
KindBinding = { label: Kind, positive_predicate: String, evidence: Set(Evidence), atomicity ∈ {atomic, non-atomic} }
-- captures the kind; if atomicity = non-atomic → split or route BEFORE certify (no value-space binding on a compound kind)
Deficit = a deficit label a kind may be claimed by — bound's own BoundaryUndefined, or one of the sibling deficits named in the route claims below. Every label this certificate can assign is inscribed in THIS SKILL.md; nothing outside this file supplies one
OwnClaim = { deficit: BoundaryUndefined, resolution: DefinedBoundary, in_scope_if: String }
-- the claim bound makes, stated as the WHOLE local morphism: the deficit it takes AND the resolution it produces. A kind is claimed here when its positive_predicate instantiates BoundaryUndefined AND the local value-space can carry it to DefinedBoundary — the bare deficit label is a name, the morphism is the predicate
DeficitFitCertificate = { own_claim: OwnClaim, route_claims: List<RouteClaim>, claimed_by: Set(Deficit), evidence: Set(Evidence), attribution_by ∈ {certificate, user} }
-- attribution_by records WHO SETTLED claimed_by: `certificate` where the fit alone settled it, `user` where the fit was ambiguous and the user's Attribution at Qa rewrote claimed_by. Written by attribute and nowhere else; read by the converge trace and the route / unattributable relays
-- fail-closed: status(c) ≠ pass BLOCKS bind_value_space. Generated by fitting KindBinding.positive_predicate against own_claim and every route_claim inscribed below — the certificate reads nothing outside this SKILL.md
-- claimed_by collects every claim the evidence supports; a SET, so "no claim holds" is the value ∅ rather than a hole in the type
status(c) = pass if c.claimed_by = {BoundaryUndefined}; route if c.claimed_by = {d} with d a route_claim's routed_deficit; ambiguous otherwise
-- read off claimed_by rather than stored beside it, so no field can drift from the claim set it is determined by
-- pass: the own claim holds alone → bind_value_space
-- route: a single route_claim's routed_deficit d holds → emit d as the typed handoff, deactivate (kind is out-of-scope for bound)
-- ambiguous: |claimed_by| ≠ 1 — several claims hold, or none holds on the evidence at hand → Qa, the one-turn disambiguation TYPED: the kind is put to the user with the claims its evidence supports, and their Attribution settles it — Own (status re-reads as pass → bind_value_space), Route(d) (route_away → deactivate), or Unattributable (deactivate with a relay of the finding; no DefinedBoundary). Never silently bind under ambiguity, and never re-sync on ambiguity alone: re-certifying unchanged ground can land ambiguous again with no terminal, so the user's attribution is what gives this arm one. Which arm is read at that turn from the user's wording, never fixed here
-- what a pass certifies is LOCAL ADMISSIBILITY: bound's own gate governing bound's own activation, not the absence of a claim anywhere in the wider protocol set. Where two protocols' scopes both reach a situation, each protocol's own gate governs
RouteClaim = (route_if_predicate: String, routed_deficit: Deficit)
-- bound-local route claims — the sibling deficits a boundary-misfit kind is handed to. routed_deficit is the BINDING field; the command in parentheses is a non-binding hint for the user, not the relation this guard composes on:
-- missing pre-execution fact → ContextInsufficient (hint: /inquire)
-- framework absent for the decision → FrameworkAbsent (hint: /frame)
-- cross-domain mapping uncertain → MappingUncertain (hint: /ground)
-- direction candidates' futures unrecognizable from description → DirectionUnrecognizable (hint: /preview)
claims_supported(k) = { d ∈ {BoundaryUndefined} ∪ { rc.routed_deficit : rc ∈ route_claims } : the evidence supports d's predicate } -- what Qa presents: the inscribed claims the captured kind's evidence supports, each with what attributing the kind to it would mean. Equal to claimed_by at the moment Qa fires; named separately because Qa also presents the case none of them holds
Attribution = Own | Route(routed_deficit: Deficit) | Unattributable -- the user's answer at Qa. A CLOSED coproduct because each constructor is a distinct processing path: Own binds the value space like any kind the fit passed; Route(d) takes the route_away deactivation; Unattributable deactivates with a relay of the finding. Route's payload is the deficit the user named — one of the claims Qa presented, or one they name themselves, emitted bare where this file inscribes no hint for it
attribute(k, a) = the step that writes the user's Attribution onto the certificate: Own → claimed_by := {BoundaryUndefined}; Route(d) → claimed_by := {d}; Unattributable → claimed_by := ∅ — and attribution_by := user on every arm. It rewrites the certificate rather than bypassing it so that every downstream reader of status(c) — bind_value_space, the invariants, the converge trace — reads the attributed value through the same function it always read. Runs on the far side of Qa's Stop, over Λ.certificate
local_claims = (OwnClaim, the RouteClaim list above) -- what certify reads beside the KindBinding; every claim it can fit is inscribed in THIS SKILL.md
V = bind_value_space : Kind → ValueSpace -- the kind is the DOMAIN (it selects each option's content), but the codomain is CONSTANT — bind_value_space returns the same coproduct for every kind; generated ONLY after status(certificate) = pass; frozen for the activation (relay / dead-signal test applied)
ValueSpace = BoundaryClassification -- the uniform settlement disposition (local_value_space; bound-local instantiation point); the same coproduct for every boundary kind — see BoundaryClassification below
cycle_n = Nat -- current cycle counter (visible at Phase 2)
-- bound index `k` ranges over `Λ.D_history` (the cycles that produced a Sub-D) in the convergence trace — NOT [1, cycle_n], since a substrate-exhaustion terminal scan increments cycle_n without producing a Sub-D
Ctx = (T, cycle_n) → Sub-D -- per-cycle context collection (re-scan)
Sub-D = { domain: Domain, scan_summary: String, evidence: Set(Evidence) } -- per-cycle dimension projection (one anchor domain per cycle)
-- Sub-D[k] = D_history[k] (k-th historical entry); current cycle = Sub-D[cycle_n]
Δessence = String -- per-cycle boundary-essence delta; produced by `integrate` at Phase 3 step 2 (integrate(typed_A?, B, BoundaryEssence) → (B', Δessence)); the termination-only fold produces the empty delta
BoundaryEssence = String -- accumulated boundary essence (crystallized form of the responsibility boundary space); initialized "" at Phase 0b loop-state init; updated as BoundaryEssence' = BoundaryEssence ⊕ Δessence at Phase 3 by `crystallize` (crystallize(Δessence, BoundaryEssence) → BoundaryEssence'), the sole producer of BoundaryEssence'
EssenceTrend(history, cycle_n) ∈ {ExtensionTrend, ConstitutionTrend, MixedTrend}
-- kind-general: the disposition trend reads only the COUNT distribution of classified dispositions across Λ.history — never kind-specific content — so it runs identically for every captured kind
-- count-based ONLY; no textual-lean interpretation — keeps derivation deterministic and relay-eligible
-- ExtensionTrend: count(AIPropose ∪ AIAutonomous) strictly dominant
-- ConstitutionTrend: count(UserSupplies) strictly dominant
-- MixedTrend: no strict dominance OR cycle_n < 2 (explicit single-cycle initialization rule — insufficient classification history to commit a non-fallback trend; cycle_n is an argument because the count rules read history while this clause reads the cycle)
DefaultClassification : {ExtensionTrend, ConstitutionTrend, MixedTrend} → {AIAutonomous, UserSupplies} ⊆ BoundaryClassification
-- kind-general per-cycle default re-derivation, applied to EssenceTrend(history', cycle_n) on loop continuation (reads disposition counts, kind-independent); DefaultClassification(MixedTrend) is the loop-state init value, since cycle_n < 2 there
-- codomain restricted to the 2-value reachable subset (AIPropose and Dismiss are unreachable from this function)
-- ExtensionTrend → AIAutonomous; ConstitutionTrend → UserSupplies; MixedTrend → AIAutonomous (Extension-default fallback)
Qc = Per-cycle boundary classification interaction [Tool: Constitution interaction]
A = the Phase 2 user response — an OPEN utterance, never a classification.
-- parse(A) → (typed_A?, TerminationIntent?) is conservative whole-utterance recognition. A commitment may be returned only when every decision-relevant part of A is coherent with and represented by that reading. If any part reframes the anchor, names an emergent concern, shifts the axis, or undercuts the apparent commitment, parse returns no commitment and Phase 2 re-presents with that material drawn directly from A in the conversation record. No separate framing carrier is needed, and no decision-relevant material can disappear down a terminal path.
-- Recognizing NO commitment (neither typed_A nor termination) is legitimate, not malformed: no map commitment exists yet. The map remains unchanged and the deliberative self-edge may stutter without an exhaustion bound; committing a disposition would exercise authority the user did not delegate.
typed_A = the cycle's classification ∈ BoundaryClassification -- recognized within the user's response on a Phase 2 cycle, or read from the substrate assignment on an auto-resolved cycle (Phase 1 auto-resolve check); its origin is recoverable from which MODE STATE partition the anchor landed in (Λ.user_responded / Λ.dismissed vs Λ.context_resolved), so the convergence trace can cite it. Drawn from the uniform settlement disposition; the presented option set is exactly this 4-value coproduct, intact per gate integrity invariant (a termination-only response carries no typed_A and is NOT an option-set extension — `Free-response separation`)
-- typed_A ∈ {UserSupplies(boundary), AIPropose(boundary), AIAutonomous(boundary), Dismiss} — the 4-value coproduct is kind-invariant; the captured kind sets what `boundary` refers to (who-decides for ownership, which-way for direction/priority, how-wide for scope, which-category for type/concept)
-- termination_intent surfaces via free-response affordance, NOT as an extra option in BoundaryClassification
TerminationIntent = parsed natural-language signal of user satisfaction
∈ {ImplicitTermination(default_override?), ExplicitTermination}
-- ImplicitTermination: residual ↦ default_at_surfacing (the Λ.default_for_residual value visible in the just-completed Phase 2 surfacing; NOT re-derived in Phase 3) OR user-stated override; terminal provenance is defined in TERMINAL CARRIERS
-- ExplicitTermination: enter Phase 4 for bulk residual classification
-- default_override : BoundaryClassification — optional user-named alternative default (a member of the uniform settlement disposition) overriding the surfaced default
B = BoundaryMap: Map(object_ref(kind), BoundaryClassification)
-- value type is the uniform settlement disposition BoundaryClassification — the SAME value type for every kind (the BoundaryMap value does NOT follow the kind; the kind sets only what content each entry's disposition is about)
-- object_ref(kind) = Domain for bound, every kind (bound-local instantiation)
-- Always-complete after each Phase 2 round: classified entries (per-cycle answers + auto-resolved) ∪ residual entries provisionally mapped to current default_for_residual
-- Snapshot completeness makes ImplicitTermination AVAILABLE at any cycle; snapshots are recognition surfaces, while TERMINAL CARRIERS exclusively defines what convergence emits.
BoundaryClassification = {UserSupplies(boundary), AIPropose(boundary), AIAutonomous(boundary), Dismiss}
-- the UNIFORM settlement disposition (local_value_space): HOW the captured kind's boundary value is settled downstream — the SAME 4-value coproduct for every kind, used across Phase 2 (per-cycle) and Phase 4 (residual bulk)
-- the OWNERSHIP kind is the degenerate case: there the boundary value being settled (who decides) IS the disposition, so disposition and content coincide — which is why this coproduct historically read as ownership-specific. For every other kind the disposition says HOW the boundary value gets settled while the kind says WHAT that value is about (direction/priority, scope, type/concept)
-- UserSupplies semantic (kind-general): user retains settlement authority for this boundary; downstream gates present open questions; user supplies the boundary value (or invokes other protocols) at decision-point activation
-- Dismiss is a COMMITTED no-boundary signal (proceed with the stated default), an on-axis disposition — not a skip; its differential future is "residual settled by default," distinct from the three active-settlement members
Qf = Final gate bulk classification interaction [Tool: Constitution interaction]
FinalGateDisposition = {UserSupplies, AIAutonomous} ⊆ BoundaryClassification -- the uniform residual-disposition subset surfaced at Phase 4, the same for every kind (the two settlement dispositions a bulk residual can take)
-- Phase 4 UserSupplies (kind-general): bulk-classify residual domains as user-retained (each residual domain becomes its own boundary; lazy-binding — values or protocol invocation deferred to downstream activation)
-- Phase 4 AIAutonomous (kind-general): bulk-classify residual as AI-settled (semantically equivalent to per-cycle AIAutonomous(boundary))
DefinedBoundary = { map: Λ.boundary_map, kind: Λ.captured_kind } where one TERMINAL CARRIERS row completed ∧ BoundaryEssence finalized
-- TERMINAL CARRIERS is the exclusive provenance definition for the result map. The kind pairing makes the map's boundary question recoverable by a later /bound seed guard and by downstream advisory consumers because object_ref(kind) = Domain does not encode the kind.
Phase ∈ {0, 0b, 1, 2, 3, 4}
── PHASE TRANSITIONS ──
Phase 0: T, B_prior? → Probe(T) → scan_B_prior(T) → Λ.B_prior → Bᵢ? -- boundary existence checkpoint + optional hermeneutic-seed DETECTION (silent); detection binds Λ.B_prior but does NOT seed B — B does not exist yet (loop state, incl. boundary_map, is initialized at Phase 0b step 4 after the kind is captured and the certificate passes, since binding is gated on a passing certificate)
[Bᵢ = ∅] Qc(zero_signal_finding) → Stop → ZeroSignalConfirmation -- zero-signal (`Zero-signal surfacing`): Confirm → deactivate (Horismos not activated) | Reopen(d) → Bᵢ := {d}, proceed to Phase 0b [Tool]
Phase 0b: T → sync_kind_route(T) → KindRouteMap → [single_dominant_kind: relay(captured_kind + basis) → proceed (extension, kind committed, NO Stop) | else: Stop → captured_kind (constitution)]
→ bind_kind(captured_kind) → KindBinding
→ certify(KindBinding, local_claims) → DeficitFitCertificate
→ (status(certificate) = pass) bind_value_space → BoundaryClassification → init_loop_state(default_for_residual = DefaultClassification(MixedTrend), B = seed_if_kind_match(Λ.B_prior, captured_kind), B_seed = Bᵢ)
-- up-front KIND dispatch + fail-closed certificate + uniform value-space, THEN loop-state init (cycle_n, BoundaryEssence, default_for_residual = DefaultClassification(MixedTrend), and the B_prior seed into B) — the seed folds into Phase 0b step 4, AFTER B is initialized, never before; seeded ONLY when kind(Λ.B_prior) = captured_kind (same boundary question), kind-mismatched prior map surfaced as advisory not seeded; Λ.B_seed := Bᵢ carries the domain signal as unclassified cycle-1 anchor candidates (non-anchored remainder residualizes at the Phase 1 residualize), separate from the classified map B (partition invariant preserved) — the formal carrier of the zero-signal Reopen(d) seed {d}, which the Phase 1 re-scan cannot be assumed to re-derive [Tool: Constitution gate | Extension relay (single-dominant-kind)]
Phase 1: T, cycle_n → Ctx(T, cycle_n) → candidates[cycle_n] → (cycle_n = 1: candidates[1] := candidates[1] ∪ (Λ.B_seed \ Λ.domains_touched)) → (Sub-D[cycle_n], auto_resolved?) → Sub-D[cycle_n].domain → Λ.domains_touched -- per-cycle context collection; cycle-1 anchor selection runs over candidates[1] = newly-surfaced ∪ (Λ.B_seed \ Λ.domains_touched) (seed joins BEFORE Sub-D binds — the seed join; a Reopen(d) seed stays an anchor candidate even when the re-scan misses it; an already-touched seed domain — e.g. B_prior-seeded into context_resolved — is excluded here and re-enters ONLY via the Ctx re-scan's stale-seed re-surface, preserving the pairwise-disjoint partition), then auto-resolve check, then the domains_touched write (the anchor commits to Λ.domains_touched and to no partition member until Phase 3 files it) [Tool]
→ (cycle_n = 1) non-anchored B_seed remainder (deduped set) → Λ.residual ∪ Λ.domains_touched; Λ.B_seed := ∅ -- cycle-1 B_seed consumption (track): non-anchored remainder of the deduped seed residualizes (the residualize write), cleared after consumption (consumed once)
Phase 2: Sub-D[cycle_n], kind, BoundaryClassification, BoundaryEssence, cycle_n, B_snapshot, default
→ Qc(Sub-D[cycle_n], kind, BoundaryClassification, BoundaryEssence, cycle_n, B_snapshot, default) → Stop → A -- per-cycle classification over BoundaryClassification with complete B_snapshot + default visibility [Tool]
Phase 3: (user-response: A → conservative parse(A) → (typed_A?, TerminationIntent?)) | (auto-resolved: typed_A = substrate-settled classification from the Phase 1 auto-resolve check, no TerminationIntent)
→ integrate(typed_A?, B, BoundaryEssence) → (B', Δessence) -- total cycle fold: a classification updates the anchor; a termination-only reading residualizes it and returns B' = B with the empty delta
→ crystallize(Δessence, BoundaryEssence) → BoundaryEssence' -- sole producer of the accumulated essence; the empty delta is the identity
→ snapshot(B', Λ.residual, default_for_residual) → B_complete' -- ALWAYS, termination folds included, and BEFORE any route: the round-local completeness invariant holds after EVERY fold, so a just-residualized anchor carries its provisional entry before any terminal write reads it
→ (only on loop continuation) DefaultClassification(EssenceTrend(history', cycle_n)) → default' → snapshot(B', Λ.residual, default') → B_complete''
-- next-cycle default (track + sense), then the snapshot that supersedes B_complete' for the cycle about to open; EssenceTrend re-derivation is kind-general (count-only over the uniform disposition)
Phase 4 (optional): residual, BoundaryEssence → Qf(residual, FinalGateDisposition) → Stop → Λ.final_gate_answers
-- final gate [Tool], reached via ExplicitTermination or Phase 1 substrate exhaustion; FinalGateDisposition = {UserSupplies, AIAutonomous}, every kind
Phase 0 → Phase 0b: boundary_undefined(T) = true ∨ ZeroSignalConfirmation = Reopen(d) -- domain signal present (probe-detected, or user-reopened seeding Bᵢ := {d}) → dispatch the kind before the loop
Phase 0 → deactivate: boundary_undefined(T) = false ∧ ZeroSignalConfirmation = Confirm -- no undefined boundary signal, zero-signal finding confirmed (`Zero-signal surfacing`)
Phase 0b sync_kind_route relay branch: single_dominant_kind(KindRouteMap, T, context) = true → relay captured_kind + basis, proceed (extension, NO turn yield) → continue to bind_kind -- entropy→0 (option-set relay test): one kind dominates, foils route away; the captured kind is committed for the activation (a rare mis-relay is corrected by re-invoking /bound, not an in-loop redirect); certify stays fail-closed
Phase 0b sync_kind_route gated branch: single_dominant_kind(KindRouteMap, T, context) = false → Stop → captured_kind (constitution) -- ≥2 viable hypotheses ∨ undecidable foil ∨ emergent gesture naming no single kind ∨ live ground leaves the emergent question undetermined → mandatory Constitution gate
Phase 0b → Phase 1: status(certificate) = pass ∧ BoundaryClassification bound -- kind captured (via relay or gate), fit certified, value-space frozen → enter the per-cycle loop
Phase 0b → deactivate (route): status(certificate) = route -- a local route claim holds the kind → route_away(RouteClaim.routed_deficit), residual untreated (kind out-of-scope for bound)
Phase 0b → Phase 0b (re-sync): KindBinding.atomicity = non-atomic -- compound kind → split, re-sync, re-certify BEFORE binding values (fail-closed); terminates because each split strictly decreases the bundled kinds
Phase 0b → attribute (CONSTITUTION): status(certificate) = ambiguous -- |claimed_by| ≠ 1 (several claims hold, or none does) → Qa(captured_kind, claims_supported) → Stop → Attribution → attribute: Own → claimed_by := {BoundaryUndefined}, attribution_by := user, status re-reads as pass → Phase 0b → Phase 1; Route(d) → claimed_by := {d}, attribution_by := user → Phase 0b → deactivate (route), with basis = the user's attribution and a command hint only where this file inscribes one for d; Unattributable → claimed_by := ∅, attribution_by := user → Phase 0b → deactivate (unattributable). ONE gate and no re-certification of unchanged ground: the user's utterance is the one new ground that can arrive, and their attribution is what gives an ambiguous certificate a terminal [Tool]
Phase 0b → deactivate (unattributable): Attribution = Unattributable -- the user found no claim that holds → relay the finding (the captured kind, the claims its evidence supported, what the user saw as unresolved), non-convergent exit; no DefinedBoundary, no BoundaryClassification bound
Phase 1 → Phase 2: Sub-D[cycle_n] non-empty ∧ ¬auto_resolved -- per-cycle anchor domain surfaced, requires user judgment
Phase 1 → Phase 3: Sub-D[cycle_n] non-empty ∧ auto_resolved -- definitive assignment found in substrate, skip Phase 2
Phase 1 → Phase 4: Sub-D[cycle_n] empty ∧ Λ.residual ≠ ∅ -- substrate-exhaustion path to explicit bulk classify (residual remains)
Phase 1 → converge: Sub-D[cycle_n] empty ∧ Λ.residual = ∅ → substrate-exhaustion terminal carrier -- every surfaced domain already classified; no empty Phase 4 gate
Phase 2 → Phase 3: A received ∧ commitment recognized (typed_A ∨ termination) -- parse recognized a commitment in the response: typed classification, termination signal, or both
Phase 2 → Phase 2: A received ∧ no commitment recognized -- re-present from A with every decision-relevant reframing made visible; the map is unchanged. This deliberative self-edge carries no monotone progress claim and no exhaustion bound: it may stutter until the user constitutes a commitment [Tool]
Phase 3 → Phase 3 (confirm): parse leaves ≥2 J routing branches viable → Qc(candidate readings) → Stop → confirmed_intent ∈ J -- `Ambiguous response routing`; routing resumes at J with the confirmed branch, which is a TerminationIntent member on the terminating branches and the absence of one on `next` [Tool]
Phase 3 → Phase 1: ¬termination_intent → derive default' → cycle_n += 1 -- continue loop with next-cycle default
Phase 3 → converge (implicit): TerminationIntent = ImplicitTermination → implicit terminal carrier -- Phase 2-surfaced default committed (NOT re-derived)
Phase 3 → Phase 4: TerminationIntent = ExplicitTermination -- user-judged satisfaction with explicit residual classification request
Phase 4 → converge: Λ.final_gate_answers covers Λ.residual → Phase 4 terminal carrier -- BoundaryMap + BoundaryEssence finalized
── TERMINAL CARRIERS ──
The table below is the sole definition of DefinedBoundary map provenance. Every graceful path starts from an initialized map source, completes its terminal write, and emits only the resulting Λ.boundary_map paired with Λ.captured_kind.
Path | Initialized source | Terminal write | Final value
Phase 3 ImplicitTermination | B' from the current cycle fold, which has ALREADY placed the anchor per the parse — a response carrying typed_A leaves the anchor classified in B', a termination-only response residualizes it; Λ.residual is read as the fold left it and is NEVER assumed to hold the anchor, so a classification the user just stated is never overwritten by the residual disposition; residual_disposition = user override when stated, otherwise default_at_surfacing | finalize(B', Λ.residual, residual_disposition) → B_final; Λ.boundary_map := B_final | { map: Λ.boundary_map, kind: Λ.captured_kind }
Phase 4 completed | Λ.boundary_map at Phase 4 entry + Λ.residual + Λ.final_gate_answers | bulk_classify overwrites every residual provisional entry, moves those domains to final_gate_classified, empties Λ.residual, and writes Λ.boundary_map | { map: Λ.boundary_map, kind: Λ.captured_kind }
Phase 1 substrate exhaustion | Λ.boundary_map at the guarded edge where Λ.residual = ∅ | identity; Λ.boundary_map is unchanged | { map: Λ.boundary_map, kind: Λ.captured_kind }
B_snapshot and B_complete' are recognition surfaces only. Neither is a result carrier, and pairing either with a kind does not constitute DefinedBoundary.
── LOOP ──
Pre-loop dispatch (Phase 0b, one-shot — runs once before the per-cycle loop opens):
sync_kind_route(T) surfaces the KindRouteMap (every recognition seed + emergent/naming path); the user captures the kind (recognize a seed, name an emergent, or extend/replace a seed).
Extension fast-path (single-dominant-kind relay): when single_dominant_kind(KindRouteMap, T, context) holds (per the single_dominant_kind predicate (TYPES) and `Option-set relay test`) — present the captured kind + its basis as relay text and proceed (the captured kind is committed for the activation), recording Λ.captured_kind with ZERO turn yields. The basis is the dominating predicate + the foils' route-away on the seed route, and the user's own naming quoted verbatim on the emergent route. The mandatory Constitution gate fires when single_dominant_kind is false — the default when in doubt; relay is the NARROW exception (`Option-set relay test`).
bind_kind → certify (fail-closed) → bind_value_space. The captured kind FIXES BoundaryClassification for the whole activation; the per-cycle loop classifies object_ref(kind) over the frozen BoundaryClassification. BOTH branches (relay and gate) feed this same pipeline — the relay collapses only the kind-capture turn yield; a non-pass certificate still gets the full gated treatment. Re-sync on ambiguous/non-atomic; route_away (deactivate) when a local route claim holds the kind.
J = {next, terminate_implicit, terminate_explicit}
(every value read below is the CONFIRMED one — a parse leaving ≥2 routing branches viable is resolved to a single branch via `Ambiguous response routing`'s one-turn confirmation gate at Phase 3 step 1 BEFORE J is evaluated, and a confirmed `next` is the absence of a TerminationIntent rather than a member of it; routing here is immediate only for an unambiguous parse)
next: ¬termination_intent → next-cycle default' (= DefaultClassification(EssenceTrend(history', cycle_n)), count-based, kind-general) → cycle_n += 1, Phase 3 → Phase 1 (per-cycle re-scan)
terminate_implicit: TerminationIntent = ImplicitTermination (parsed from Phase 2 free response) → Phase 3 → converge with residual filled by default_at_surfacing (the Λ.default_for_residual value Phase 2 surfaced — NOT re-derived) or user-stated override; a termination-only response (no typed selection) first residualizes the current anchor (Phase 3 step 2), so it is included in that fill
terminate_explicit: TerminationIntent = ExplicitTermination (parsed from Phase 2 free response) → Phase 3 → Phase 4 (final gate)
Per-cycle re-scan: Phase 1 substrate scan (artifact read/artifact search) re-executes each cycle; `Λ.domains_touched` (anchored ⊔ non-anchored ⊔ resolved/dismissed) is the dedup source — no domain surfaced twice.
Cycle 1 ordering: AI Impact ordering selects highest-impact domain.
Cycle k≥2 ordering: previous cycle's typed_A[cycle_n-1] or free-response routes next cycle's domain selection frame; AI re-applies Impact ordering within the routed frame.
Answer types (members of the uniform disposition BoundaryClassification: UserSupplies/AIPropose/AIAutonomous/Dismiss) determine BoundaryMap entry, not loop path.
FinalGateDisposition (the uniform subset {UserSupplies, AIAutonomous} ⊆ BoundaryClassification, every kind) determines residual BoundaryMap entries at Phase 4.
Round-local BoundaryMap invariant: after each Phase 3 integrate — termination folds included, since the snapshot refresh is NOT conditioned on loop continuation — `Λ.boundary_map` snapshot is always complete: classified entries ∪ (residual ↦ default_for_residual). Snapshot completeness makes ImplicitTermination available AND gives every residual domain the provisional entry the Phase 4 bulk_classify overwrite reads, so no domain reaches a terminal write without an entry; TERMINAL CARRIERS governs every emitted result.
Convergence evidence: At convergence (Phase 3 ImplicitTermination ∨ Phase 4 completed ∨ substrate-exhaustion empty-residual), present transformation trace — per-cycle (Sub-D[k], Δessence[k], disposition[k]) for each anchored cycle k (k ranges over Λ.D_history — the cycles that produced a Sub-D; a substrate-exhaustion terminal scan produces no Sub-D and contributes no entry; disposition[k] ∈ BoundaryClassification is READ FROM the finalized Λ.boundary_map entry for Sub-D[k].domain, never re-declared per terminal path — the trace evidences the emitted map, so it carries the map's own value for that domain whichever path assigned it; Δessence[k] is the delta integrate produced for cycle k, or the empty delta when the cycle produced no classification), plus residual disposition:
Cover: the parts together range over the domains of the EMITTED Λ.boundary_map, each domain reported exactly once. "non-anchored d" means d ∉ { s.domain | s ∈ Λ.D_history } — compared on DOMAIN IDENTITY, since D_history holds Sub-D projections while the partition sets hold Domains, and a raw membership test across the two types would fail to exclude an auto-resolved anchor. Anchored membership takes precedence, so a domain anchored in some cycle is reported only as a per-cycle entry even when it also sits in context_resolved (auto-resolved), residual (the termination-only anchor), or final_gate_classified. Every other map domain — a kind-matched B_prior seed left unchanged in context_resolved, a non-anchored domain accumulated into residual, a bulk-classified domain — is reported by the matching part below. A map domain in neither part is a gap in the evidence, not an omission the trace may make.
• ImplicitTermination: ∀ non-anchored d ∈ residual: (d, default_at_surfacing_or_override) — basis follows which value committed: the EssenceTrend / count-distribution derivation when the surfaced default committed (kind-general), the user's stated override when one did
• Phase 4 completion: ∀ non-anchored d ∈ final_gate_classified: (d, Λ.final_gate_answers[d]) -- the partition bulk_classify moved them into; Λ.residual is empty by then
• Seeded-and-unchanged: ∀ non-anchored d ∈ context_resolved: (d, disposition(d)) — cites the substrate assignment or the prior-classification seed basis; these never anchored a cycle, so nothing else reports them
• substrate-exhaustion empty-residual: residual = ∅ — no residual disposition (every surfaced domain classified per-cycle)
BoundaryEssence is presented as separate session text artifact. Convergence is demonstrated, not asserted.
── CONVERGENCE ──
converge iff (Phase 3 ImplicitTermination ∨ Phase 4 completed ∨ substrate_exhaustion_empty_residual) ∧ status(certificate) = pass
certificate gate: convergence presupposes a passing DeficitFitCertificate (Phase 0b); a route certificate, or an ambiguous one the user left unattributable, never reaches the loop, and an ambiguous one reaches it only on the user's Own attribution — so DefinedBoundary is unreachable without an in-scope, fit-certified kind, certified on the evidence or on the user's word. The pass certifies LOCAL admissibility — bound's own gate over bound's own activation — not the absence of a claim anywhere in the wider protocol set
kind_dispatch_branch: the captured kind reaches the loop via EITHER branch of Phase 0b sync_kind_route — the single_dominant_kind relay (extension, no turn yield) or the mandatory Constitution gate — and both flow through the fail-closed certificate, so convergence is branch-invariant: a relay-captured kind whose certificate is route (routes away/deactivates) or ambiguous (goes to Qa, and reaches the loop only on an Own attribution) is handled exactly as the gated branch's is
unattributable_deactivate: Phase 0b Attribution = Unattributable → relay the finding, non-convergent exit (no DefinedBoundary emitted; the evidence did not settle the certificate and the user did not settle it either — reported, never silently bound or silently dropped)
Phase 3 ImplicitTermination: the Phase 3 ImplicitTermination row in TERMINAL CARRIERS completed
Phase 4 completed: the Phase 4 row in TERMINAL CARRIERS completed — reachable via Phase 3 ExplicitTermination OR Phase 1 substrate exhaustion with residual remaining
substrate_exhaustion_empty_residual: the substrate-exhaustion row in TERMINAL CARRIERS completed under Sub-D empty ∧ Λ.residual = ∅
route_deactivate: Phase 0b status(certificate) = route → route_away(RouteClaim.routed_deficit), non-convergent exit (kind out-of-scope for bound; no DefinedBoundary emitted)
── TOOL GROUNDING ──
-- Realization: Constitution → TextPresent+Stop; Extension → TextPresent+Proceed
Phase 0 Probe (sense) → Internal analysis (silent — no user output; heuristic boundary-undefined detection + session-context scan for a prior BoundaryMap as Λ.B_prior (DETECTION only — Phase 0 seeds nothing; a kind-matched prior is seeded at Phase 0b step 4, a kind-mismatched prior stays advisory-only); notice visibility deferred to Phase 2 cycle 1 surfacing)
Phase 0 ZeroSignalConfirm (constitution) → present (conditional: Bᵢ = ∅; zero-signal finding + reasoning; Confirm/Reopen(Domain) — `Zero-signal surfacing`)
Phase 0b sync_kind_route (constitution) → present (GATED branch — fires when single_dominant_kind = false: ≥2 seeds stay viable under the framing, a seed's route-away is undecidable from the framing, an emergent gesture resolves to no single naming, OR the live ground (T, context) leaves the emergent question undetermined; up-front KindRouteMap — one hypothesis for every recognition seed, each with positive_predicate + evidence + differential_future + route-away conditions, plus an emergent/naming free-response path; named kinds are PRIORS not a closed set; user captures the kind by recognizing a seed, naming an emergent, or extending/replacing a seed)
Phase 0b sync_kind_route_relay (extension) → TextPresent+Proceed (RELAY branch — fires when single_dominant_kind = true, per the single_dominant_kind predicate (TYPES) and `Option-set relay test`. Present the captured kind + its basis as relay text — the basis quotes the user's own wording rather than paraphrasing it wherever the emergent conjunct carried the decision, and quotes it VERBATIM when the relay fires because the user already named the emergent kind, since there that wording IS the capture — and proceed, recording Λ.captured_kind WITHOUT a turn yield; the captured kind is committed for the activation (like the gated branch) — a rare mis-relay is corrected by re-invoking /bound, not an in-loop redirect transition. The fail-closed certify STILL runs on this branch — a non-pass DeficitFitCertificate gets the full gated treatment (route → route_away/deactivate, ambiguous → re-sync), so the relay never bypasses deficit-fit)
Phase 0b certify (sense) → Internal analysis (extension — fail-closed DeficitFitCertificate; deterministic check of KindBinding.positive_predicate against the own claim and the route claims inscribed in this SKILL.md, reading nothing outside this file: claimed_by = {BoundaryUndefined} when the own claim holds alone; status(certificate) = pass | route | ambiguous; basis = the cited claim fit, shown at Phase 2 cycle 1's first surfacing; ambiguous → Qa, the certificate itself binding nothing and closing nothing under ambiguity)
Phase 0b Qa (constitution) → present (conditional: status(certificate) = ambiguous. Presents, as text before the gate, the captured kind, its evidence with its channel, and what the certificate found — the claims that evidence supports, or that none does; the gate itself carries the question "whose is this?" and the Attribution options with their differential implications: the own claim → the boundary is defined here, the value space binds and the loop opens; each supported route claim → handed to that deficit, with the command hint this file inscribes for it, and this activation ends; none of these → the finding is relayed and this activation ends with no boundary defined. A deficit the user names outside the presented set is a Route(d) answer emitted bare. One turn, once: the user's attribution is written by attribute and read by every downstream reader of status(certificate). Constitution because the certificate has already said what the evidence settles, and what it does not settle is not the AI's to decide — `Ambiguity surfaces`)
Phase 0b attribute (track) → Internal state update (writes the user's Attribution onto Λ.certificate — claimed_by rewritten to {BoundaryUndefined} / {d} / ∅ and attribution_by := user. Runs on the far side of Qa's Stop and nowhere else; the deactivation or binding that follows is the arm the attributed status selects)
Phase 0b unattributable_deactivate (extension) → TextPresent+Proceed (conditional: Attribution = Unattributable → relay the finding — the captured kind, the claims its evidence supported, what the user saw as unresolved — and deactivate; no DefinedBoundary, no value space bound)
Phase 0b bind_value_space (track) → Internal state update (extension — generate the uniform settlement disposition {UserSupplies, AIPropose, AIAutonomous, Dismiss} ONLY after status(certificate) = pass; same coproduct for every kind; relay / dead-signal test applied; freeze BoundaryClassification for the activation. On status(certificate) = route → route_away(routed_deficit), deactivate — reached also through the user's Route(d) attribution at Qa, with basis = that attribution; on KindBinding.atomicity = non-atomic → re-sync Phase 0b before binding; on status(certificate) = ambiguous → Qa, and binding only on an Own attribution)
Phase 1 Ctx (observe) → artifact read, artifact search (per-cycle re-scan: CLAUDE.md, project rule files, prior session context)
Phase 1 (track) → Internal state update (cycle 1 only: Λ.B_seed candidates (minus Λ.domains_touched) enter anchor selection alongside newly-surfaced domains; non-anchored remainder of the deduped seed → Λ.residual ∪ Λ.domains_touched — partition invariant preserved; Λ.B_seed := ∅, consumed once)
Phase 2 Qc (constitution) → present (mandatory; per-cycle classification over BoundaryClassification + captured-kind label + essence-refinement preview (NOT the committed Δessence, which integrate produces at Phase 3 step 2) + cycle_n + current B_snapshot + current default_for_residual with count-distribution basis cite + cycle-1 certificate-fit basis + cycle-1 notice when Λ.B_prior non-empty (seed notice when kind-matched, advisory-only notice when kind-mismatched) + free-response termination affordance with implicit/explicit sub-signals)
Phase 3 parse (sense) → Internal analysis (conservative whole-utterance recognition with no Λ mutation: return typed_A? + TerminationIntent only when the reading accounts for all decision-relevant meaning in A; otherwise return no commitment and let Phase 2 re-present directly from A)
Phase 3 confirm_intent (constitution) → present (conditional: a parse leaving ≥2 J routing branches viable — present the candidate readings that parse actually left open (ImplicitTermination committing residual at default_at_surfacing | next continuing to the following cycle | ExplicitTermination proceeding to Phase 4), each with its differential future, and Stop; the user's confirmation or correction routes the loop at J — `Ambiguous response routing`)
Phase 3 (track) → Internal state update (integrate(typed_A?, B, BoundaryEssence) → B', Δessence as the total current-cycle fold; a termination-only commitment returns B' = B, residualizes the anchor, and supplies the empty delta; crystallize applies to every delta with the empty delta as identity; ImplicitTermination executes the Phase 3 TERMINAL CARRIERS write; on loop continuation only — DefaultClassification(EssenceTrend(history', cycle_n)) → default' (kind-general, count-only); the B-snapshot refresh runs on EVERY fold, termination included, taking default' on continuation and the current default_for_residual on termination, so the completeness invariant leaves no gap for a terminal write to read)
Phase 4 Qf (constitution) → present (residual bulk classification over FinalGateDisposition = {UserSupplies, AIAutonomous}, every kind; reached via ExplicitTermination or substrate exhaustion)
Phase 4 (track) → Internal state update (bind the complete final_gate_answers map, then execute the Phase 4 TERMINAL CARRIERS write)
converge (extension) → TextPresent+Proceed (captured-kind + DeficitFitCertificate basis + per-cycle trace + residual disposition trace + BoundaryEssence artifact; proceed with defined boundary)
Seam transition to declared next protocol (extension) → TextPresent+Proceed (fires at deactivation/handoff: a user-declared chain naming the next protocol settles the next move — proceed directly to it, citing that settling source. This protocol declares no wired outbound continuation edge: a route claim fires when status(certificate) = route, a pre-loop out-of-scope route-away that deactivates before any DefinedBoundary, not a post-convergence handoff, so the second trigger is vacuously absent. Every Constitution gate inside this protocol and inside the next protocol fires unchanged)
── MODE STATE ──
Λ = { phase: Phase, T: TaskScope,
kind_route_map: Optional(KindRouteMap), -- Phase 0b dispatch sync (every recognition seed + emergent path)
captured_kind: Optional(Kind), -- the kind the dispatch settled on (recognize-seed | name-emergent | extend/replace-seed); set via the single_dominant_kind relay (extension, no turn yield) OR the mandatory Constitution gate
kind_binding: Optional(KindBinding), -- fields: label, positive_predicate, evidence, atomicity
certificate: Optional(DeficitFitCertificate), -- fields: own_claim, route_claims[], claimed_by, evidence, attribution_by; fail-closed gate — status(certificate) must = pass before value_space binds; attribute rewrites claimed_by here on the far side of Qa's Stop
value_space: Optional(ValueSpace), -- the uniform settlement disposition; frozen for the activation once status(certificate) = pass (UserSupplies / AIPropose / AIAutonomous / Dismiss, same for every kind)
B_prior: Optional(SeededPrior), -- hermeneutic seed detected at Phase 0 (a SeededPrior — prior BoundaryMap plus the kind it was produced over); the carried kind (B_prior.kind) is what Phase 0b step 4 tests to gate seeding to same-kind only (kind-mismatched prior map → advisory, not seeded)
B_seed: Set(Domain), -- = Bᵢ, the Phase 0 domain-signal seed (the singleton d on zero-signal Reopen(d)); carried across the Phase 0 → 0b transition (both Stops sit between production and consumption); kept separate from the classified map B — B_seed is a Set(Domain), B a Map — and consumed at Phase 1 cycle-1 anchor selection as unclassified candidates; the non-anchored remainder residualizes at the Phase 1 residualize (→ Λ.residual ∪ Λ.domains_touched) and B_seed clears after cycle 1
cycle_n: Nat,
domains_touched: Set(Domain), -- accumulated across cycles (Phase 1 surfacing union)
D_history: List<Sub-D>, -- per-cycle dimension projections
essence_history: List<Δessence>, -- per-cycle delta accumulation
boundary_essence: BoundaryEssence, -- accumulated essence text
default_for_residual: BoundaryClassification member, -- provisional residual disposition surfaced each Phase 2 (a member of the uniform disposition); DefaultClassification(EssenceTrend(history, cycle_n)) re-derived each cycle, every kind
context_resolved: Set(Domain), -- Phase 1 auto-resolved (Bᵣ-equivalent, per-cycle) ∪ B_prior-seeded domains (Phase 0b step 4 init; basis: "prior classification" — entries mutable across cycles, may be re-surfaced by Phase 1 if a stale-prior signal is detected)
user_responded: Set(Domain), -- Phase 2 BoundaryClassification classification completed (the uniform 4-value disposition)
final_gate_classified: Set(Domain), -- Phase 4 bulk classification completed
dismissed: Set(Domain),
residual: Set(Domain), -- unclassified subset of domains_touched (implicit-delegation candidates; provisionally mapped to default_for_residual in boundary_map snapshot)
boundary_map: BoundaryMap, -- always-complete after each Phase 3: classified entries ∪ (residual ↦ default_for_residual)
final_gate_answers: Map(Domain, FinalGateDisposition),
history: List<(Domain, BoundaryClassification)>,
active: Bool, cause_tag: String }
-- Invariant: domains_touched = context_resolved ∪ user_responded ∪ final_gate_classified ∪ dismissed ∪ residual (pairwise disjoint)
-- Scope: holds at every cycle boundary — after each Phase 3 and at every Phase 1 entry. The one transient exception is the cycle's own anchor between the Phase 1 domains_touched write (which commits it there) and Phase 3 step 2 (which files it into a partition member): across the Phase 2 Stop the anchor is in domains_touched and in no member, by construction, since the member it belongs to is what Phase 2 is asking. Every path out of Phase 2 — typed answer or termination-only — reaches a step that files it.
-- Invariant: boundary_map = classified_entries(context_resolved ∪ user_responded ∪ dismissed ∪ final_gate_classified) ∪ (residual ↦ default_for_residual) — round-local completeness
── COMPOSITION ──
*: product — (D₁ × D₂) → (R₁ × R₂). Dimension resolution emergent via session context.
Dispatch-first rationale: BoundaryMap is a multi-consumer router. The captured kind must settle BEFORE the per-cycle loop opens — hence bound carries the up-front Phase 0b sync rather than emerging the kind cycle-by-cycle: downstream consumers reading a stable kind cannot tolerate a kind that shifts mid-loop. The DeficitFitCertificate (checked against the own claim and the route claims inscribed in this SKILL.md) keeps a misfit kind from entering the shared map — a kind a local route claim holds is routed away (deactivate) instead of polluting the multi-consumer signal. What a pass certifies is LOCAL admissibility, bound's own gate governing bound's own activation, not the absence of a claim anywhere in the wider protocol set: where two protocols' scopes both reach a situation, each protocol's own gate governs.
Hermeneutic carry-over (kind-aware): an optional B_prior input (prior BoundaryMap detected in session context, together with the kind it was produced over) seeds the new invocation ONLY when its kind matches the captured kind (same-kind — same boundary question). Every kind shares the uniform disposition, so a mismatched prior's values are type-compatible; the guard is SEMANTIC: a kind-mismatched prior answers a DIFFERENT boundary question, so it is surfaced as advisory context, NOT seeded into boundary_map (seeding it would commit a wrong-question disposition into the multi-consumer signal). Seed entries are mutable in subsequent cycles and BoundaryEssence is re-crystallized from the current task scope. The seed enables a feedback loop where a downstream observation refines a prior BoundaryMap through re-invocation.
Round-local BoundaryMap composition: each Phase 2 cycle produces a complete BoundaryMap (classified entries ∪ residual ↦ default_for_residual). The complete snapshot is citable as scope text for a realization-layer turn-condition primitive — the AIAutonomous and AIPropose entries delineate an Extension-progression scope whose exhaustion is a natural completion condition orthogonal to the in-protocol satisfaction signal that emits DefinedBoundary.
What ships with it
1 file beside SKILL.md in the same directory: the scripts, references and assets a skill reads on demand. Not counted in the per-session cost; read them before you install if any of them is executable.
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- today Changed · +10 lines a30052cb4e62
- yesterday Changed · -1 lines 3d6560b5058e
- 5d ago First seen · 351 lines · 41 tokens per session scan A 077b9ec7053e
bound is a skill published in the GitHub repository jongwony/epistemic-protocols (160 stars, last pushed today), licensed MIT. It adds 41 tokens to every session and 16,097 once invoked, about $0.0002 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-30.
Other skills, from other repositories
taiyi-ui-design
TaiyiForge 第 4 阶段 — UI/UX 契约,产出 UI-DESIGN.md。四端通用。.
flow-next-resolve-pr
Resolve PR review feedback. Fetches unresolved threads, triages, fixes, replies and resolves via GraphQL. Use when asked to address review comments.
flow-next-tracker-sync
Project a flow-next spec to a tracker issue (Linear, GitHub, GitLab, Jira) and reconcile two-way. Use when asked to sync to a tracker. NOT plan-sync.
taiyi-evolve
TaiyiForge 辅助 — 实现后架构与文档同步(architecture-sync)。OpenCode / Claude / Codex / Cursor 通用。.
taiyi-diagram-c4
TaiyiForge 辅助 — 从代码反推 C4 架构文档(Observed/Inferred 分层 · Mermaid 真源)。OpenCode / Claude / Codex / Cursor 通用。.
flow-next-prime
Assess codebase agent and production readiness. Classifies the project, verifies commands run, leads with a verdict and ranked next actions.