Commit graph Ghostlight/docs
Author SHA1 Message Date
Meta Vens
d8dce9db5e Fix docs stale after Cut 1's teardown (PA.f15)
Cut 1 (d69e9d4) deleted the tick driver and the Active elaboration sweep, and
the ignored live smoke that exercised them. These passages still described
that machine as live:

- notes/local-live-smoke.md was a runbook for the deleted smoke and its
  command now runs zero tests. Trimmed to what is still true: connector and
  Claude SDK sidecar bring-up, which the seed lane still depends on. Fixed
  the references to its deleted sections in notes/fresh-workspace-handoff.md.
- docs/architecture/ghostlight-dungeon-mvp.md's Verification contract named
  the live smoke as the road's one proof point; it now says none exists until
  the play agent's own gate.
- notes/ghostlight-implementation-plan.md's Interruption section named
  ControllerHttpResult::Interrupted and run_cover_tick as live; both are
  deleted, and reporting an interruption to the play agent is Cut 8's.
- docs/architecture/ghostlight-stock-lenses.md gets one added sentence: the
  concurrent-elaboration claim holds as a library capability, and Dungeon
  runs none of it since Cut 1. The verdict is unchanged.
- notes/fresh-workspace-handoff.md's concurrent-elaboration and
  tick-driver lines now say what Dungeon actually runs today.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 02:27:59 +02:00
Meta Vens
aee9279c84 Record play agent Cut 2 as landed at 182f803
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 02:17:43 +02:00
Meta Vens
d15ff86155 Record Soul verdicts on play agent Cut 1 and triage its findings
All four promises hold. P1.1 and P1.2 are unguarded by any test (PA.f11),
and the only test of the receipt kinds was dropped (PA.f12). Both are to
fix, along with the stale docs (PA.f15). PA.f13 and PA.f14 go to Cut 8.
The negative grep now allows the one hit at M1.1's test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 01:59:03 +02:00
Meta Vens
273242ba3f Record play agent Cut 1 as landed at d69e9d4
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 01:49:16 +02:00
Meta Vens
d69e9d43cf Delete Dungeon's autonomous drivers and owner controls (play agent Cut 1)
Nothing in Dungeon now runs a Persona, an operational agent or an
elaborator on its own. Deleted from runtime.rs: the cover tick driver
(drive_cover_tick, drive_one_tick, run_cover_tick, submit_clock_tick,
CoverSummary, InterruptedCell, cover_panel, the clock-tick constants,
configured_cover_budget, configured_tick_interval), the Active
elaboration sweep (elaborate_world, run_elaboration_sweep,
ELABORATION_SWEEP_INTERVAL, configured_elaboration_ceiling,
AppState.elaboration_permits), and the owner's "Let X act" route
(ControllerActPayload, dispatch_controller, admit_controller_command,
ControllerHttpResult and its builders, controller_error_disposition).
Deleted from eve.rs: CoverPanel, CoverPanelTick, cover_card, the owner's
controller buttons and descriptor, and world.controller.act from
operation_schema.

AppState.controller_quarantined is deleted as well: its only writers were
dispatch_controller and run_cover_tick, so it could never be set again.

controller_permits and configured_controller_concurrency stay for Cut 8;
until then only runtime_readiness reads the pool. ControllerRunner stays
for seeding and custody_probe; world.speak, the story card and
world.advance_time stay until Cut 9.

Tests dropped with the behaviour they pinned: the nine the cut map lists,
plus no_proposal_projection_carries_the_canonical_world_commit, which
tested the deleted controller_submission. Their fixtures go with them;
the world fixture collapses to the Draft-only path its remaining callers
use. removed_legacy_operation_is_denied_before_dispatch now also names
world.controller.act.

Docs: the MVP doc, the ontology and the handoff drop the cover,
tick-interval and elaboration-ceiling variables and the sentences that
described the deleted drivers.

Library untouched. Built and tested on Windows only.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 01:45:57 +02:00
Meta Vens
29f9ab3402 Respecify Cut 3 for Ruled facts and minted quantity (PA-Q15)
Cut 3 now adds a unit FactStanding::Ruled and a new ComponentOp::Mint
rather than reshaping Admit. It adds one post-resolution author check,
require_ruler, which refuses either one unless the caller is
System(Play). The evidence gate is unchanged for every author, Play
included. The work-row bump to v17 moves into Cut 3.

PA-Q10 and Q12 are folded in as ruled designs. PA-Q7's list becomes 25
tools, with mint in and admit out. table_view prints ids, holdings, and
each fact with its standing and who knows it.

New findings: PA.f9 (the shared catalog shows mint and ruled to the seed
and elaborator lanes; watched at the gate), and PA.f10 (minted quantity's
only provenance is the commit caller; a question for the outbound pass).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 01:25:56 +02:00
Meta Vens
37be2cef1a Record the play agent rulings: six forks, Ruled facts, minted loot
The operator accepted the map's recommendation on PA-Q1, Q3, Q7, Q10, Q12
and Q13 on 2026-09-22. The operator also ruled PA-Q15: the play authority's
facts stand as Ruled, and it mints quantity without evidence ("if the agent
can invent people, it can invent loot"). Only Play gains either;
elaborators, consumers and the seed keep the evidence gate.

The target now lists the library's fourth piece (the table vocabulary and
inference seams) and the affordance grants. Invariant 5 gains Ruled facts
and minting, and invariant 8 shows the kernel's refusal of the player's own
act. Cut 3 still specifies the superseded PlayCarriesEvidence refusal and
is being respecified.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 01:20:52 +02:00
Meta Vens
cf81cbe034 Map the play agent cut (plan step 16)
Imagination's cut map for the play agent target. Probes compiled a scratch
consumer against the library, and the agent's tool catalog was measured.
The map answers target questions Q1-Q14. Q2, Q5, Q6, Q8 and Q9 are
defaulted, Q4 and Q14 are findings, and Q11 is ruled by the operator.
Q1, Q3, Q7, Q10, Q12 and Q13 await operator rulings.

Ten cuts follow, subtraction in Dungeon first, then the local port, the
kernel pieces (play authority, retirement, affordance grants), the Persona
lane, the table vocabulary, the play table, and the Eve surface. Findings
PA.f1-PA.f8; PA.f1 was already resolved at 5ff1d54.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 01:12:28 +02:00
Meta Vens
5ff1d54efa Point the state surfaces at the play agent gate
The map, handoff, plan and Session Zero doc now name plan step 16, the play
agent, as the playtest gate. L2-L4, D1-D3 and the L1 follow-ups are
recorded as deferred by ruling, not dropped.

A source check corrected the map. Inference routes per lane by model name
to the SDK sidecar or CodexConnector, and no local transport exists. The
sidecar is a private msgpack pipe behind InferencePort, not the CultNet
connector API the map claimed every backend shares.

The handoff's session_zero.begin item is retired: the name is refused, and
only tests reference it. One evidence record covers the pivot.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 00:53:24 +02:00
Meta Vens
4e61f586bf Rule play agent Q11: the Projector renders the player's view
The operator ruled on 2026-09-22 that the player's perception goes through
the same Projector a Persona gets, which makes the Projector the player's
narration. The play agent writes none. The turn description and invariant 8
now say so.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 00:53:24 +02:00
Meta Vens
cb0b604ae3 Write the play agent target (plan step 16)
The operator redirected the playtest gate on 2026-09-22. Ghostlight's
controller machinery suits offline simulation, not interactive role-play.
One operational agent now runs the table; the Projector and Persona passes
stay exactly as they are.

The target records the rulings (the play authority, actor acts through the
actor's affordances, deferral of L2-L4, D1-D3 and the L1 follow-ups), eight
invariants, the redefined playtest gate, and eleven open questions for the
cut map.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 00:49:02 +02:00
Meta Vens
bd25d0fffe Sync the last surfaces after L1
The closing memory pass found four stale spots:
- The ontology still said the schemas are consumer.v3, contradicting
  consumer.v5 in the same paragraph. The sentence is gone.
- Evidence record 21 said each world carries a typed detail rule, which
  is L3 and not built. It now says a world will carry one.
- Evidence record 20 pointed at the design section. It now points at the
  landed L1 target.
- The system map's "Current acceptance body" describes the legacy release
  Yggdrasil still serves. It is now headed as pre-rebuild, so its titled
  worker text no longer reads as live.

Evidence is rewritten through compact-evidence, which archives the old
text.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 20:10:02 +02:00
Meta Vens
576c8ac667 Close L1: postmortem, ledger, target and docs reconciled
The stock lenses pass is closed.
- The ghostlight library ships eight lenses.
- Worlds carry weights as world data, and the owner can replace them.
- Each elaborator session draws its lens replayably and records the lens and
  its instruction text.
- Sessions run concurrently under their own permit ceiling.
- In-flight work is found again by reading the store.
All eight target invariants hold.

The cut map records the second Cut 4 fix batch, Soul's final pass, Cut 5's
verdicts and the ledger's actuals. The actuals are +4,907 / −266 in crates
against about +1,300 estimated, the overrun overwhelmingly tests that caught
real defects.

Recorded as follow-ups: an Uncovered case the tests do not pin (L1.f15), and
whether consumers may supply their own lens sets (L1.f16, the operator's).

The target is rewritten as reconciled. The ontology loop no longer claims
seed requests or Vault evidence for the Active sweep, the handoff says
lens weights, and map.yaml names L2 as next.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 20:08:25 +02:00
Meta Vens
b15ade4d08 Name world_create.v4 beside the seed producer in the MVP doc (L1 Cut 5)
The verification contract named creation only as step 8's `world.create` v2.
It now states the current payload, `world_create.v4`, with its required
fields including lens weights, and that Dungeon's create surface offers
uniform weights as its editable default.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 19:56:30 +02:00
Meta Vens
39b2af4237 Describe the landed lenses and concurrent sweep in the ontology (L1 Cut 5)
"Elaborators" states the per-sweep claim set, the caller-owned ceiling and
Dungeon's two pools, and its loop takes a demand entry, resumes an in-flight
session answering it, and otherwise draws and records a lens.

"Elaboration lenses and detail rules" says which bullets L1 implemented and
which L2 to L4 still owe. The Lenses bullet describes the live mechanism:
weights required at creation, replaced by the owner through SetLensWeights in
any phase, a draw from world id and command id, lens and instruction text on
the checkpoint, LensWeightsNeverDraw and NoCanonicalChange refusals. The stock
set is closed. The cut list drops the sequential per-jurisdiction sweep.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 19:54:47 +02:00
Meta Vens
01312dd45d Record L1-Q10, the panic ruling, and the Cut 4 fix batch
The operator ruled L1-Q10 option A: the in-flight listing excludes rows
ready to submit, and the crash window goes under L1.f14. The operator
also agreed to the panic handling. A session-task panic becomes an error
returned after its siblings finish, and the driver keeps running.
Quarantine stays with L1.f1.

The fix batch landed at 6f35229..0764842. Soul's second pass confirmed the
new permit guard releases exactly once on every exit path, including
cancellation, and that a panicked session is adopted cleanly. It found the
adoption rule reachable through the sweep only by ready-to-submit boundary
rows.

Findings folded into the Cut 5 pass: pin that a retryable error does not
stop the sweep, pin that Uncovered work is swept alongside a deficit, and
delete a proven-dead digest comparison. Recorded for L1.f1: a panic during
a checkpoint write would wedge the lane with only debug-level logging.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 19:41:04 +02:00
Meta Vens
21edecaff9 Record L1 Cut 4's landing, verdicts and findings
Cut 4 landed at 8538fab..3e35b3d. Soul's first pass confirmed:
- distinct claims and the permit ceiling;
- deficit adoption, with no adoption across jurisdiction, world or a
  NoPatch row;
- a listing read once per sweep;
- claims taken before any await, and sweeps that cannot overlap.

Going to a fix batch:
- Cut 3's adoption rule now rests on one test;
- speak-turn pool independence is untested;
- the sweep's Active-only gate is unpinned;
- the Uncovered jurisdiction is never swept in a test;
- a panic in one session task silently kills the elaboration driver
  until restart. That fix makes a task panic an error returned after its
  siblings finish, and leaves quarantine handling to L1.f1.

L1-Q10 asks the operator whether the in-flight listing excludes rows
ready to submit. Soul measured both sides: including them stalls every
committed deficit forever; excluding them costs one repeated round and one
orphan in a crash window. L1.f14 records that stored rows are never
retired.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 18:58:26 +02:00
Meta Vens
b3963f911d Run elaboration sessions concurrently over a per-sweep claim set (L1 Cut 4)
Rulings L1-Q4 (revised) and L1-Q9 (A).

Library (elaboration.rs):
- The sequential per-jurisdiction loop and step(jurisdiction) are deleted.
  ElaborationOutcome loses Clean and Inactive, which nothing produces now.
- sweep(permits) takes one snapshot and returns Ok unless the world is
  Active. It reads the store's in-flight listing once, builds the claim set,
  and spawns one step_session per entry into a JoinSet. Each session holds a
  permit from the caller's pool for its whole step.
- Every spawned session finishes before sweep returns. A quarantine-class
  error is returned after that, and no session starts after one has returned
  such an error. The sequential loop's early return also started no further
  session. Any other error is logged at debug.
- demand_entries is the claim set. For each swept jurisdiction it takes
  every covered boundary in derivation order, then the deficit if nonzero.
  Each entry is matched against the listing by world, jurisdiction and
  answer before anything is drawn. A match adopts the row's session and
  command id; if several match, the oldest is adopted and the rest are
  logged as orphans. An unmatched entry derives its id and draws its lens
  (fresh_session). An answer is claimed once, and so is a command id.
- step_session(command_id, session, snapshot) is the old step body. Its
  lookup and Cut 3's adoption rule are unchanged.
- step_in(jurisdiction), test-only, steps the first entry of one
  jurisdiction's claim set, so the Cut 3 tests keep reading one session's
  outcome.

Store: the listing now returns only ElaboratorInFlight rows. A committed
session ends in ReadyToSubmit, so listing that stage adopted a committed
deficit row, and every later sweep resubmitted it (AlreadyApplied) instead
of opening the next deficit session. That departs from the map's listing
contract.

Dungeon: elaborate_world and the ignored road test pass
state.elaboration_permits to sweep. The driver doc states that sweeps never
overlap.

Tests: 12 library tests.
- Concurrency: distinct_entries_run_at_once_under_the_ceiling,
  the_sweep_never_exceeds_its_ceiling, a_sweep_holds_a_permit_while_it_infers,
  one_answer_is_one_session_per_sweep.
- Claim set: a_boundary_under_nested_roots_is_claimed_once,
  a_deficit_entry_is_one_per_jurisdiction_per_ancestry.
- Errors: a_retryable_fault_ends_only_its_own_session,
  a_quarantine_error_is_returned_after_every_session_finishes.
- Rediscovery: a_stranded_deficit_session_is_adopted_with_its_refusal_intact,
  a_boundary_session_is_repaired_after_a_commit_and_a_tick,
  the_store_gains_no_orphan_per_commit, a_row_for_another_answer_is_not_adopted.

Dungeon adds saturating_one_pool_never_delays_the_other. The dead-end
fixture can now declare its commons (or commons and a ward) as a
jurisdiction root, with a subject that holds a goal, because a sweep visits
only jurisdictions that have a deficit row. The Cut 3 tests call step_in.

Docs: ghostlight-world-ontology.md states the concurrent sweep as the
shipped rule.

Counts: library 456 + 1 ignored, Dungeon 53 + 1 ignored. This commit
builds.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 17:44:04 +02:00
Meta Vens
6150bd7667 Split Dungeon's controller pool into simulation and elaboration (L1 Cut 4)
Ruling L1-Q4: neither lane may starve the other, and the elaboration pool is
a ceiling rather than a budget.

- AppState gains elaboration_permits beside controller_permits.
  controller_permits stays the simulation budget, which speak turns and
  cover cells draw from.
- configured_elaboration_ceiling() reads GHOSTLIGHT_ELABORATION_MAX_CONCURRENT
  at open, in the same shape as the simulation pool: default 2, minimum 1.
- The speak handler's comment now names both pools.
- The test fixture opens the second pool with TEST_ELABORATION_CEILING = 2.
- docs/architecture/ghostlight-dungeon-mvp.md names both variables and what
  each pool means.

This commit builds with one warning more than its parent:
elaboration_permits is never read. The next commit passes the pool to the
elaboration sweep, and the warning goes away there.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 17:09:43 +02:00
Meta Vens
d9b71c49fd Record the Cut 3 test-only fix batch
The batch landed at f63dfd1, b3b5053 and 2c3b513 with no production
change.

- The flaky illegal-transition test failed 3 of 40 runs before and passed
  120 of 120 after.
- The call-site draw is now pinned to the session's own command id across
  eight multi-lens worlds.
- A resumed session is proven to keep its stored instruction text, which
  was the operator's purpose for Q7.

Both mutations that previously survived, S3 and S5, now fail. Cut 4's Soul
pass reruns them in place of a separate pass on a test-only batch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 16:59:42 +02:00
Meta Vens
ef6400884a Record L1 Cut 3's landing, verdicts and findings
Cut 3 landed at dfb3c52..2bf8164. Soul's first pass confirms that
boundary sessions now resume after unrelated commits, that a resumed
session keeps its recorded lens across a weight change, that admission is
the same under every lens, and that the catalog and session identity are
unchanged. It also observed all three illegal transitions (lens, text,
ancestry), and a stale adopted draft is still refused by the kernel.

Going to a test-only fix batch:
- the illegal-transition test is flaky, failing roughly one run in eight;
- nothing pins that the call-site draw reads the command id;
- nothing pins that a session resumes with its stored instruction text,
  which was the whole point of the Q7 ruling.

Recorded: stored text is not tied to the recorded lens (inside Q7's
accepted cost); a route cost change re-rolls a boundary session's lens and
orphans its row; the seed lane orphans rows the same way deficits do
(L1.f13). The ledger text no longer doubles "recorded".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 16:42:12 +02:00
Meta Vens
18b1098c3f Record the lens and its text on the session; adopt rows by answer (L1 Cut 3)
A new elaborator session draws its lens and authors its instruction text
once, and the checkpoint row carries both from then on. A resume reads the
row's session instead of demanding the fresh derivation equal it.

Session:
- `ElaboratorSession` gains `lens: Lens` and `instructions: String`
  (`deny_unknown_fields` kept).
- `select_answer` derives the command id from world, jurisdiction and
  answer digest, draws `lens::draw(snapshot.lens_weights, world, id)`, and
  authors `lens.instructions()`. It returns the id with the session, and
  `step` uses that id instead of deriving it a second time.
- `session_command_id` takes the three identity fields instead of a session,
  because the lens is drawn from the id and so the id exists before the
  session does. The derivation bytes are unchanged: the Cut 0 id
  `56dbcdb2-9337-ac07-f322-37376b58cbcb` is pinned in
  `a_session_identity_is_derived_from_its_answer`.
- `ELABORATION_INSTRUCTIONS` moves into `lens.rs` as a private constant.
  `elaboration_request` takes the text, and `step`, `persist_repair` and
  `integrity_is_valid` pass `session.instructions`. Integrity binds the
  stored invocation to the stored text, not to code (L1-Q7 (a)).

Adoption rule (L1-Q9, boundary half): the whole-session supersession
equality in `step` is deleted. A found row is this answer's row when world,
jurisdiction, answer and answer digest match (`same_answer`). Its session,
including ancestry, lens and text, replaces the fresh one. A boundary session
is no longer `Superseded` forever after an unrelated commit.
`valid_elaboration_progression` is unchanged and still compares whole
sessions row to row; the doc comments on both rules say why they differ.

Store: `controller_work.v15` -> `v16`; v15 rows are refused at open, not
migrated. The world ontology doc names v16.

Tests (controllers): `a_boundary_session_resumes_after_an_unrelated_commit`
(at 1a402e1 it reported Superseded),
`a_resumed_session_keeps_its_recorded_lens_when_the_weights_change`,
`a_checkpoint_that_changes_the_lens_or_its_text_is_an_illegal_transition`,
`a_row_whose_text_and_invocation_disagree_is_refused_at_open`,
`a_controller_work_row_from_v15_is_refused_at_open`,
`soul_the_same_patch_admits_the_same_under_every_lens` (pinned to the
Cut 0 mismatch JSON), and `the_catalog_takes_no_lens`. The single-dead-end
fixture now delegates to `dead_end_mailbox(weights, dead_ends)`, which builds
the first dead end with the same handles and labels as before.

Builds, but with two "this lint expectation is unfulfilled" warnings from
the `expect(dead_code)` markers on `Lens::instructions` and `lens::draw`. The
next commit removes those markers (c1.s1.f3).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 16:07:25 +02:00
Meta Vens
1a402e1d45 Record the Cut 2 fix batch, Soul pass 2 and two operator rulings
The fix batch landed at afca403 and acb9b33: identical lens weights are
refused as no canonical change, and the forged all-zero row is now caught
only by the draw rule. Soul's second pass found that the no-op check
compares map spelling, so a set padded with a zero entry still commits.
That fix is folded into Cut 3, next to the divisor guard.

The Cut 2 spec's claim that identical weights commit is now marked as
history. The implementation plan names a NoEffect variant that the kernel
never had; it now describes the NoCanonicalChange refusal that exists.

Operator rulings: the browser create form (L1.f11) is fixed in Dungeon
pass D2. Draft approvals (L1.f12) are deferred until multi-player
membership returns, and lens weights are excluded from any future binding
because they do not affect what an approver sees.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 15:45:58 +02:00
Meta Vens
c8dfdd1a35 Record L1 Cut 2's landing, verdicts and findings
Cut 2 landed at d06fd7e and 10be98c. Soul's first pass finds every promise
holding except the browser half of P2.6, which is unproven. The owner
check has a single source, and no ingress lets a caller supply its own
authority.

To fix before Cut 3: an identical SetLensWeights commits a no-op revision,
against the kernel's rule that a no-effect command commits nothing. The
forged all-zero journal-row test is caught by the digest, not the draw
rule.

Recorded for the operator: the browser create form never lifts its
bindings into the payload, for any field (L1.f11, relevant to the playtest
gate). Draft approvals are bound to nothing, so an approval survives later
weight and structure changes (L1.f12).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 15:26:07 +02:00
Meta Vens
10be98cce7 Name consumer.v5 and world_create.v4 in the world docs (L1 Cut 2)
The ontology names world_create.v4 with its required lens weights and the
consumer.v5 state and commit schemas; the consumer API names consumer.v5.
Docs only; builds as the previous commit does.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 15:00:45 +02:00
Meta Vens
3cb6a74bb0 Record L1 Cut 0 captures and Cut 1's landing and verdicts
Cut 1 landed at 835ea4d, and Soul's first pass records all five promises
as holding. External code can build an all-zero LensWeights through
new, Default or Deserialize but cannot reach the draw, because the lens
module and draws are private. So there is no crash path, which matches
L0's unforgeable-admission ruling.

Soul findings:
- duplicate keys are last-wins, like every BTreeMap field in the crate
  (recorded);
- the all-zero guard and the divisor are different computations, a
  hardening fix that goes to Cut 3;
- a leftover expect(dead_code) produces a warning, not a compile error,
  which corrects Hands' claim.

Cut 0's captures and the census baseline are now recorded, and so are
Cut 1's ledger actuals. The ledger no longer says the draw lives inside
the session identity, which the Q4 revision removed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 14:40:45 +02:00
Meta Vens
ff766e8901 Rule L1-Q9: resume reads in-flight elaboration state
The operator ruled that an in-flight elaborator session is rediscovered by
reading state, not by re-deriving its key. Cut 4 adds one store method
listing in-flight elaboration rows, scanned once per sweep. The sweep
matches rows by world, jurisdiction and answer, ignoring ancestry, lens
and instruction text, and adopts the row and its id before any draw. The
command id stays the kernel's idempotency key and stops being the only way
to rediscover work.

New promises prove the fix, and each fails when adoption is removed: a
stranded deficit session is adopted with its refusal and without a
repeated round; a boundary session is repaired after an unrelated commit
and a clock tick; no orphan row accumulates over five ticks; real-shaped
non-matches are never adopted.

L1.f10 is resolved by Cut 3 for boundaries and Cut 4 for deficits.
Every question L1-Q1 through L1-Q9 now carries a ruling. Estimated total
+1,300 lines.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 14:11:42 +02:00
Meta Vens
d3b2c0e464 Keep the lens out of command identity; find the stranded repair loop
The operator revised L1-Q4: the lens is recorded on the session and stays
out of the command id, because the id is the idempotency key and must be
a fixed property of the demand entry it answers. That dissolves L1-Q8 and
its eight-candidate-id probing. L1-Q7 is ruled: per-lens instructions,
with their text persisted in the checkpoint.

The operator then asked whether resume relied on re-deriving an id
instead of reading state. It does, and a probe found that the elaborator's
repair loop has never worked across sweeps (L1.f10, pre-existing, high).
A deficit session's key moves on any commit, so the next sweep repeats
the inference without its refusal and orphans the old row. A boundary
session is found, but its stored ancestry makes it Superseded forever
after any commit, including a clock tick.

Cut 3 carries the equality fix that boundaries need. L1-Q9 asks whether
resume should read in-flight rows by what they answer.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 14:04:56 +02:00
Meta Vens
b846c68a28 Map the stock lenses cuts (plan step 15, L1)
Six cuts against 817c9f4: captures, the lens module, lens weights as
world data with an owner command (consumer.v5), the lens on the session
and in the prompt (controller_work.v16), concurrent elaboration under split
permit pools, and doc reconciliation.

Status is derived rather than maintained. A question is open until it
carries a ruling with its authority, and a cut is closed when every
promise has a verdict.

The operator ruled on the seed, weights in the world, the owner weights
command, split pools, emphasis as prompt text, and explicit weights at
creation with world_create.v4. Q7 (where lens text lives) is open with a
probed recommendation. Q8 was defaulted and is under review.

Probes, all on Windows: two sessions on one answer collide today; a
lensed session survives reopen and resume under v16; storing instructions
in the checkpoint passes integrity through resume and repair; the Dungeon
test count differs by four Linux-only tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 13:24:25 +02:00
Meta Vens
817c9f45ea Write the stock lenses target (plan step 15, L1)
L1 gives elaboration in the ghostlight library a creator-controlled flavor.
The library ships eight stock lenses, a world carries lens weights as world
data, and each elaborator session draws one lens deterministically. Several
sessions may elaborate at once.

The target names eight invariants: lenses never decide admission, every
lens sees the whole catalog, the draw is replayable with no RNG, weights
are admitted honestly, concurrent sessions stay distinct, the drawn lens
is recorded and never redrawn on resume, stores refuse rather than
migrate, and no Dungeon concept enters the library.

It also records the constraints the substrate map found, and the open
questions Imagination must bring back. Status is derived from the cut map,
not maintained by hand.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 12:45:03 +02:00
Meta Vens
d86ed9f4a2 Close L0: postmortem, ledger, target and state reconciled
The kernel extraction is finished. The world kernel is the ghostlight
library crate; Dungeon consumes it across a boundary sealed by admission,
proven from outside the crate.

The cut map records the last two fix batches and Q1-10, defaulted: the
minter scanner stays a tripwire, with Clippy recorded as the fix. The
subtraction ledger missed its estimate, +210 net source lines against about
+65. The reasons: the scanner grew chasing evasions, the boundary needed
about 90 more public items than planned, and the rejection tests buy a
ruling made after the estimate.

The postmortem lists what Soul caught, the operator corrections, the
incidents, and the open follow-ups. The target states which invariants
hold and how. The plan, map.yaml and the handoff point at L1. The L0
evidence record is rewritten as its distilled lessons; the previous text is
archived.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 12:24:49 +02:00
Meta Vens
89eb75b6a7 Record the Cut 1 fix batch and Soul's verdict
The fix batch landed at 7c1d1e9..2865ea7: external rejection tests,
the minter check by name, Eve removed from library text, and a narrower
public surface. Soul confirmed the rejection tests drive the real kernel
path from outside the crate, that the unchanged-state assertions are
sound, and that Hands was right about what holds three types public.

Soul also found the digest check is pinned only by forgeries of the wrong
length, so a stale same-length digest from an earlier revision is going to
a fix. The minter scanner is still evadable five ways; since every text
scanner in this migration has lost to a short evasion, Q1-10 asks whether
Clippy's disallowed-methods should replace it.

Recorded, not fixed: rustc on stable does not enforce compile_fail error
codes, the world_id check is redundant by construction, and the decline
path is not reachable from an external test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 11:47:08 +02:00
Meta Vens
7c1d1e96fa Rule Q1-9: sealing means unforgeable admission
External code may hold a syntactically valid ID, digest or opportunity,
because Dungeon's Eve payloads deserialize them. What must hold is that
the kernel rejects every one it did not issue, proven by rejection tests
written from outside the crate. The compile_fail set stays for the
genuinely private items, with its limit stated: it pins a path name and
cannot see constructibility.

The target's first invariant now says that, so the claim matches what the
boundary does.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 10:42:25 +02:00
Meta Vens
af63b0cd13 Record Soul's verdict on the Cut 2 fix batch
The batch holds: whole-invocation pinning survives image swaps, line
swaps, re-indentation, continuation splits and appended flags; the order
checks catch a move into the reuse branch; the runbook is tied in both
directions; and a fail inside a command substitution does abort.

Soul then found the limit of the approach. An exact-line pin proves the
lines exist, not that they run: wrapping the block in `if false`, chaining
it behind `true ||`, or swallowing it in a heredoc keeps every pinned line
intact and the checker green. Abort on failure rests on an unpinned
`set -euo pipefail`, and a duplicated block passes unnoticed.

All three are recorded, not fixed. The script is a legacy actuator under a
do-not-invoke warning, retired at the deployment gate, and the authority
that really runs the tests is Ghostlight's Idunn recipe. Revisit only if
the gate keeps the script.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 02:57:01 +02:00
Meta Vens
8ddc1e86f3 Record the Cut 2 fix batch and its follow-ups
gamecult-ops 803f2c7 pins each of the four cargo steps as a whole
docker invocation, asserts the recipe order, and brings the runbook into
the wiring test. The four mutations that previously passed silently now
fail, and no pre-existing assertion was weakened.

The same defect class survives in three places outside this migration:
the web build container, the Codex Connector's cargo steps, and a fixed
18-line search window. All three are recorded as follow-ups.

Soul has not yet passed on the fix batch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 02:47:28 +02:00
Meta Vens
e7d21013b9 Record Soul's Cut 2 verdict
The assertions Cut 2 added pin text, not invocations. Deleting the two
lines above the pinned cargo line turns it into trailing arguments on the
previous container: the kernel tests never run and the wiring test still
passes. Nothing pins the order of the four cargo steps, and the wiring
test never reads the runbook.

Those three are going to a fix batch. Two more are recorded, not fixed: a
redeploy of an already-sealed commit runs no cargo steps at all, which is
pre-existing deploy behaviour the operator owns, and the dated census docs
still show the old single-crate paths.

What held: the library step runs in the right branch with the same image
and mounts, its failure aborts the deploy, and the acceptance test path
resolves under the library crate.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 02:40:45 +02:00
Meta Vens
1b409b3121 Record Cut 2 and the two spec defects it exposed
Cut 2 landed at gamecult-ops 6aba281: the library test step now runs in
the deploy script, is documented in the runbook, and is asserted by the
wiring test. Without it a deploy would run 50 tests and skip the 420
kernel tests that moved to the library crate.

Two defects in this map's own spec, reported by Hands rather than worked
around:
- the assertion it specified was vacuous, because require_text is a
  substring match and the given string is a substring of the
  persona-projection line;
- the acceptance test path lives in a variable the spec did not list,
  pinned by the wiring test and repeated in the runbook prose.

Changing the acceptance binding means sealed acceptance witnesses from
before this commit will miss and regenerate.

Soul has not passed on Cut 2 yet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 02:35:06 +02:00
Meta Vens
880c9656ad Record Cut 1 and Soul's verdict; sync the stale surfaces
Cut 1 landed at 108b691..f859d2c. Soul reran the builds, tests, census and
mutations itself and confirmed the behavior-unchanged claim; it found six
defects.

F1 is the one that matters: the seal is name-based. Public ID types,
ScopeDigest and DecisionOpportunity all derive Deserialize, so an external
crate can mint them from JSON and rebuild the fixture path ruling Q1-4
said must be unreachable. The reducer still rejects forged opportunities,
so kernel integrity holds while the invariant's wording does not. Q1-9 asks
the operator whether sealing means unforgeable admission or unconstructible
types.

F2 (bypassable minter count) and F3 (71 unused public items) are queued for
the fix batch. F4 names Eve in library error strings. F5 and F6 are
recorded, not fixed.

The map, map.yaml and the handoff now say the kernel is the ghostlight
crate.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 02:27:09 +02:00
Meta Vens
f859d2c4e3 Give the world library a sealed public boundary
Completes the move begun in the previous commit, which does not build on its
own. `ghostlight` is now a library crate with an explicit public surface;
`ghostlight-dungeon` is a consumer that reaches the kernel through it and
cannot reach past it.

Deleted first: `mod world;`, the nine unused re-exports, the `#[cfg(test)]`
re-export block, `fixture_controller_opportunities`, the five inference
`fixture_*` items, Dungeon's own `VerifiedPrincipalEvidence`, and Dungeon's
direct `ghostlight-persona-projection` dependency.

The seal. `WorldKernel`, `WorldState`, `reduce`, `apply_effect`,
`CommandEnvelope`, `AuthenticatedCaller`, the journal writer, every ID
`issue()`, and `ScopeDigest::fixture` carry no `pub` of any kind and no
feature gate; the crate declares no `[features]`, so no build configuration
can lift them. Ten `compile_fail` doc-tests stand outside the crate and pin
each one to its error code.

The principal seam. The library owns `VerifiedPrincipalEvidence` with a public
`new`; `mailbox` still bounds it by `valid_until` at ingress. A Dungeon test
counts the minters in production source and fails at anything but one.

The port contract (Q1-7). `PreparedInference::prepare` (renamed from the free
`prepare_invocation`), `InferenceOutput::new`, and
`InferenceFault::{retryable, recovery_required, integrity_violation}` are now
the port's public constructors, so a consumer-implemented `InferencePort` can
answer without test-only wrappers. `TracingInferencePort` is an ungated
decorator.

The tick-ordering test (Q1-8) derives its cover from a real active world
through `derive_cover` and asserts two cells; its ordering and shared-tick
assertions are unchanged.

Behaviour is unchanged. The library's 420 unit tests are the base `world::`
set with the prefix stripped — the names diff empty. Dungeon keeps all 49 of
its names and gains two Soul tests the boundary requires. No schema string,
digest preimage, or store layout is touched.

Windows verification only; the Linux release is Idunn's build.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 02:06:07 +02:00
Meta Vens
6ddabcad33 Record the L0 rulings; close the fixture question
Rulings Q1-1 through Q1-6 are in the map's status header. The crate is
`ghostlight`. The Vault reader and the SDK port go in the library. The
library owns the principal evidence type. The persona projection crate
stays separate. The gamecult-ops cargo lines are edited, not retired,
and editing them is not an endorsement to run those helpers.

Ruling Q1-4 asked for the Dungeon tests that need sealed fixtures to move
into the library. Classification found none to move: all five are Dungeon
runtime tests. Two further rulings close it instead:
- Q1-7: the inference port's value constructors become the port's public
  contract and the five fixtures are deleted.
- Q1-8: the cover ordering test derives its cover from a real world, and
  the last fixture reaching a sealed ID constructor is deleted.

The sealed ID issuers and ScopeDigest::fixture stay private under every
configuration, with no feature gate anywhere.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 01:27:37 +02:00
Meta Vens
02bbf62eb1 Map the library extraction cuts
The Imagination pass maps plan step 15 L0 against d83534c:
- Cut 0: base captures (469 bin tests, and a world.cc written at base).
- Cut 1: a single Ghostlight commit that moves world/ into a library
  crate with the exact public boundary (compile_fail doc tests prove the
  sealed items) and a test-support feature for cross-boundary fixtures.
- Cut 2: the gamecult-ops cargo invocations.

The map was probed with scratch cargo checks on the Windows workstation,
so it proves Windows only. Six operator questions are open. No code has
moved.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 23:27:03 +02:00
Meta Vens
d83534cf38 Write the library extraction target; merge conflicting boundary records
Plan step 15 pass L0 extracts the world kernel from crates/ghostlight-dungeon
into its own library crate. The new target document lists the invariants
that must survive:
- sealed kernel visibility at the crate boundary;
- no change in behavior, schemas, or stores;
- no Dungeon concepts or dependencies in the library;
- a working release path;
- unaffected pins;
- bounded build fan-out.

It also lists the questions Imagination must bring back.

Two evidence records from 2026-09-15 disagreed about focus and whether the
extraction and title decisions were settled. They are now one boundary
record. The title correction now points at the ontology doc's lens section.
The compaction archived the previous records verbatim.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 22:57:01 +02:00
Meta Vens
e19c9d9bda Replace focus with typed detail rules; ship titles as stock lenses
A detail rule is a function from place to detail level. Each consumer
chooses its own level-of-detail rule. Dungeon uses ByDistance anchored on
important subjects, the player first. Delvehold starts from Uniform.

Rules are typed world data that the library evaluates, not consumer code.
The deficit a rule produces is an admission input, and journal replay
re-runs reduce, so a changed consumer function would break committed
history. WorldScaleIntent per-kind targets remain the ceiling a rule
distributes.

The eight titles move into the library doc as the stock lens set. The
kernel extraction is ordered as plan step 15 pass L0, ahead of every
library pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 22:55:18 +02:00
Meta Vens
3d5fe83708 Keep Session Zero in Dungeon; spec the library capabilities it consumes
Ghostlight Dungeon is a consumer of the Ghostlight library. Session Zero,
Vault choice, players, sliders and starting locations are Dungeon authority
and do not shape the library.

The ontology doc gains consumer-neutral library targets: elaboration
lenses with weights, focus-weighted demand with a consumer-supplied detail
profile, one evidence source bound per world, and elaborator sessions in
Draft. The Session Zero doc now carries only Dungeon policy that consumes
those capabilities.

The map records the boundary as a hard rule. The plan splits into library
passes L1-L4 and Dungeon passes D1-D3. Two decisions stay open: extracting
the kernel from crates/ghostlight-dungeon, and whether the eight titles ship
as a library stock lens set.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 22:46:54 +02:00
Meta Vens
038632d1dd Align remaining doc lines with titled lenses and Session Zero
The memory steward found four leftover lines. The plan and the ontology
doc now describe elaborators as lensed sessions, not eight fixed
instances. The handoff no longer says there is no Session Zero. The
ontology doc notes that Session Zero stops declaring the human at the
genesis commons.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 22:34:39 +02:00
Meta Vens
25ff91f08d Restore the titled elaborators as lenses and design Session Zero
The eight titles (Patina, Charter, Ledger, Hearth, Tangle, Veil, Ember,
Numen) were deleted with their titled verifier and quotas, and no operator
decision covered them. The ontology doc and evidence record 6 now say the
tribunal was the verifier and the quotas, not the titles. A new correction
record carries the history and the 2026-09-15 direction.

Session Zero is the player's path through a world's Draft phase. The player
chooses a Vault, describes the experience, and sets title weights. The seed
lane sketches the world and the player chooses a start. A swarm then draws a
title by weight for each session and elaborates by travel distance from the
player, before and after activation. It is plan step 15, and its fifth pass
closes the playtest gate.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 22:33:21 +02:00
Meta Vens
cc016ffb55 Name CultLib as the home of the TypeScript CultNet client
The contract doc still pointed at the standalone GameCult/cultnet-ts repo,
which is being removed. The client is the cultnet-ts package in CultLib.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 16:47:39 +02:00
Meta Vens
22937b71f0 Replace vendor/cultcache-py submodule with published PyPI dependency
CultLib's packages/cultcache-py is now published as cultcache-py==0.2.0 on
PyPI (MIT), so the standalone GameCult/cultcache-py fork that Ghostlight
vendored as a submodule is retired. Symbol-for-symbol and on-disk-format
verification against the pinned submodule commit 9b4bbb8 found no
incompatibility: every symbol tools/ghostlight_state_store.py imports
(CultCache, JsonLinesBackingStore, define_document_type) and every method it
calls kept its signature, and JsonLinesBackingStore's on-disk JSONL envelope
fields and sort order are unchanged, confirmed by a real round-trip against
Ghostlight's production state/ghostlight-state.cultcache.jsonl.

tools/ghostlight_state_store.py no longer pushes vendor/cultcache-py/src onto
sys.path; it imports cultcache_py directly. Since Ghostlight's session
bootstrap previously depended on the submodule needing no install step,
tools/requirements.txt now pins cultcache-py==0.2.0 and npm run
state:bootstrap (pip install -r tools/requirements.txt, idempotent) runs as a
pre-hook ahead of state:status and state:prepare-compaction; AGENTS.md's
Session Bootstrap protocol and Useful Commands section call it out explicitly
for the direct ghostlight_state.py CLI invocations that don't go through npm.

Verified for real: `python tools/ghostlight_state.py status` and `python
tools/ghostlight_prepare_compaction.py`, run from a venv with cultcache-py
installed from PyPI, against Ghostlight's actual production state file (22 ok
findings, 2 pre-existing unrelated warnings, exit 0 both times).

Idunn's deployment/idunn/recipe.toml never declared vendor/cultcache-py in
required_gitlinks (only vendor/eve) and its build/test/service steps never
touch Python state tooling, so no recipe change is needed for admission.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 16:08:19 +02:00
Meta Vens
9574bf53d7 Point the economy spec at GameCult/Njordr
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 18:29:10 +02:00
Meta Vens
78e54554b8 Njordr: discovery as a producer policy, retooling as a recipe, catalog generation plan
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 18:15:15 +02:00