Add coordinator artifact seam
This commit is contained in:
parent
6e43aa2bd8
commit
43eea254de
9 changed files with 1457 additions and 10 deletions
251
examples/coordinator/cold-wake-sanctuary-intake.v0.json
Normal file
251
examples/coordinator/cold-wake-sanctuary-intake.v0.json
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
{
|
||||
"schema_version": "ghostlight.coordinator_artifact.v0",
|
||||
"artifact_id": "coordinator.cold_wake.sanctuary_intake.v0",
|
||||
"review_status": "accepted_as_draft",
|
||||
"fixture_lane": "historical_grounded",
|
||||
"canon_status": "single_history",
|
||||
"source_refs": [
|
||||
{
|
||||
"ref_id": "cw_grounding",
|
||||
"path": "examples/lore-grounding/cold-wake-panic.ganymede-corridor.json",
|
||||
"purpose": "Grounds the sanctuary intake scene in Cold Wake corridor pressures."
|
||||
},
|
||||
{
|
||||
"ref_id": "cw_fixture",
|
||||
"path": "examples/agent-state.cold-wake-story-lab.json",
|
||||
"purpose": "Provides scene, agent, relationship, memory, and object state."
|
||||
}
|
||||
],
|
||||
"input_refs": {
|
||||
"agent_state_ref": "examples/agent-state.cold-wake-story-lab.json",
|
||||
"lore_grounding_refs": [
|
||||
"examples/lore-grounding/cold-wake-panic.ganymede-corridor.json"
|
||||
],
|
||||
"prior_artifact_refs": [
|
||||
"experiments/ink/cold-wake-sanctuary-intake-qwen-sequential-v10-no-think.capture.json"
|
||||
],
|
||||
"projected_context_refs": [
|
||||
"examples/projected-contexts/scene-02-sanctuary-intake.maer_tidecall.projected-context.json",
|
||||
"examples/projected-contexts/scene-02-sanctuary-intake.sella_ren.projected-context.json"
|
||||
],
|
||||
"ink_refs": [
|
||||
"examples/ink/cold-wake-sanctuary-intake.qwen-sequential-v10.ink"
|
||||
],
|
||||
"item_manifest_refs": []
|
||||
},
|
||||
"scene_context": {
|
||||
"scene_id": "scene-02-sanctuary-intake",
|
||||
"sequence_marker": "after Maer brings a corrupted packet to the sanctuary intake desk",
|
||||
"location_id": "ganymede_corridor.sanctuary_intake",
|
||||
"participant_ids": [
|
||||
"maer_tidecall",
|
||||
"sella_ren"
|
||||
],
|
||||
"active_object_ids": [
|
||||
"corrupted_distress_packet"
|
||||
],
|
||||
"active_resource_ids": [
|
||||
"sanctuary_bed_capacity",
|
||||
"ledger_backing"
|
||||
],
|
||||
"public_facts": [
|
||||
{
|
||||
"text": "The sanctuary has limited capacity and must decide whether a corrupted packet represents a claimant worth intake resources.",
|
||||
"refs": [
|
||||
"cw_grounding",
|
||||
"cw_fixture"
|
||||
]
|
||||
}
|
||||
],
|
||||
"scene_pressure": [
|
||||
{
|
||||
"text": "Maer carries Navigator rescue obligation; Sella carries triage obligation and must not let mercy theater bankrupt the clinic.",
|
||||
"refs": [
|
||||
"cw_grounding",
|
||||
"cw_fixture"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"coordinator_decision": {
|
||||
"decision_id": "decision.sanctuary.packet_assessment",
|
||||
"selected_next_beat": "Maer exposes enough packet evidence for Sella to evaluate the intake risk without pretending personhood is proven.",
|
||||
"selected_acting_agent_id": "maer_tidecall",
|
||||
"candidate_next_beats": [
|
||||
{
|
||||
"choice_id": "beat.show_packet",
|
||||
"summary": "Maer routes the packet through the shared clinic display and asks Sella to judge the math.",
|
||||
"status": "selected",
|
||||
"reason": "Keeps Maer embodied as a Navigator using mixed wet/dry interface affordances and preserves Sella's authority."
|
||||
},
|
||||
{
|
||||
"choice_id": "beat.argue_personhood",
|
||||
"summary": "Maer argues that the packet is definitely a person.",
|
||||
"status": "rejected",
|
||||
"reason": "Would collapse the unresolved claimant status and overclaim evidence."
|
||||
}
|
||||
],
|
||||
"rationale": "The scene needs pressure without false certainty: Maer should act from obligation and evidence, while Sella should retain triage authority and room to distrust the packet.",
|
||||
"glue_prose": "The intake desk did not become kinder because a Navigator arrived with a grief-shaped packet. It became more expensive.",
|
||||
"glue_prose_status": "accepted_as_narration"
|
||||
},
|
||||
"machinery_plan": {
|
||||
"invocations": [
|
||||
{
|
||||
"invocation_id": "invoke.project.maer",
|
||||
"organ": "projector",
|
||||
"purpose": "Compile Maer-local operating context for the action choice.",
|
||||
"input_refs": [
|
||||
"examples/agent-state.cold-wake-story-lab.json"
|
||||
],
|
||||
"output_refs": [
|
||||
"examples/projected-contexts/scene-02-sanctuary-intake.maer_tidecall.projected-context.json"
|
||||
],
|
||||
"status": "accepted"
|
||||
},
|
||||
{
|
||||
"invocation_id": "invoke.respond.sella",
|
||||
"organ": "sandboxed_responder",
|
||||
"purpose": "Generate Sella's local response from projected context and the visible packet action.",
|
||||
"input_refs": [
|
||||
"examples/projected-contexts/scene-02-sanctuary-intake.sella_ren.projected-context.json"
|
||||
],
|
||||
"output_refs": [
|
||||
"experiments/ink/cold-wake-sanctuary-intake-qwen-sequential-v10-no-think.capture.json"
|
||||
],
|
||||
"status": "accepted_as_draft"
|
||||
},
|
||||
{
|
||||
"invocation_id": "invoke.mutate.v10",
|
||||
"organ": "state_mutator",
|
||||
"purpose": "Apply reviewed manual state and relationship consequences after the accepted draft branch.",
|
||||
"input_refs": [
|
||||
"experiments/ink/cold-wake-sanctuary-intake-qwen-sequential-v10-no-think.capture.json"
|
||||
],
|
||||
"output_refs": [
|
||||
"examples/agent-state.cold-wake-story-lab.after-v10-packet-assessment.json",
|
||||
"experiments/ink/cold-wake-sanctuary-intake-qwen-sequential-v10.mutation.json"
|
||||
],
|
||||
"status": "accepted_as_draft"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sandboxed_responder_handoffs": [
|
||||
{
|
||||
"handoff_id": "handoff.sella.v10",
|
||||
"responder_agent_id": "sella_ren",
|
||||
"projected_context_ref": "examples/projected-contexts/scene-02-sanctuary-intake.sella_ren.projected-context.json",
|
||||
"visible_input_ref": "experiments/ink/cold-wake-sanctuary-intake-qwen-sequential-v10-no-think.capture.json#passes.sella_response_generation.prompt",
|
||||
"hidden_context_refs": [
|
||||
"maer_tidecall.private_state",
|
||||
"author_only.branch_future",
|
||||
"coordinator.rationale"
|
||||
],
|
||||
"isolation_method": "external_model_packet_only",
|
||||
"raw_output_ref": "experiments/ink/cold-wake-sanctuary-intake-qwen-sequential-v10-no-think.capture.json#passes.sella_response_generation.response",
|
||||
"reviewed_output_ref": "examples/ink/cold-wake-sanctuary-intake.qwen-sequential-v10.training.json",
|
||||
"coordinator_interventions": [
|
||||
{
|
||||
"intervention_type": "normalization",
|
||||
"description": "Materializer normalized accepted capture into Ink and sidecar annotations without treating glue prose as state."
|
||||
}
|
||||
],
|
||||
"leakage_audit": {
|
||||
"private_state_leak": false,
|
||||
"author_only_leak": false,
|
||||
"future_branch_leak": false,
|
||||
"raw_state_soup": false,
|
||||
"prompt_parroting": false,
|
||||
"body_or_object_omniscience": false,
|
||||
"notes": [
|
||||
"Accepted as draft; future gold responder data should use subagent_no_fork or equivalent sandboxing rather than old Qwen plumbing."
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"world_state_refs": {
|
||||
"read_refs": [
|
||||
{
|
||||
"ref_id": "state.scene",
|
||||
"ref_type": "scene",
|
||||
"path": "examples/agent-state.cold-wake-story-lab.json#scenes.scene-02-sanctuary-intake",
|
||||
"visibility": "coordinator_only"
|
||||
},
|
||||
{
|
||||
"ref_id": "state.relationship.maer_sella",
|
||||
"ref_type": "relationship",
|
||||
"path": "examples/agent-state.cold-wake-story-lab.json#relationships.maer_tidecall.sella_ren",
|
||||
"visibility": "coordinator_only"
|
||||
}
|
||||
],
|
||||
"write_candidate_refs": [
|
||||
{
|
||||
"ref_id": "state.after_v10",
|
||||
"ref_type": "event",
|
||||
"path": "examples/agent-state.cold-wake-story-lab.after-v10-packet-assessment.json#events",
|
||||
"visibility": "coordinator_only"
|
||||
}
|
||||
]
|
||||
},
|
||||
"proposed_deltas": [
|
||||
{
|
||||
"delta_id": "delta.packet_assessment.memory",
|
||||
"delta_type": "memory_write",
|
||||
"target_ref": "maer_tidecall.memory",
|
||||
"summary": "Maer remembers that Sella demanded ledger backing rather than accepting an appeal to rescue obligation.",
|
||||
"authority": "manual_review",
|
||||
"status": "accepted",
|
||||
"rationale": "Captured in v10 mutation receipt."
|
||||
},
|
||||
{
|
||||
"delta_id": "delta.sella.read",
|
||||
"delta_type": "perceived_overlay_update",
|
||||
"target_ref": "sella_ren.perceived.maer_tidecall",
|
||||
"summary": "Sella sees Maer as evidence-driven but still capable of importing costly obligations into her clinic.",
|
||||
"authority": "manual_review",
|
||||
"status": "accepted",
|
||||
"rationale": "Keeps Sella's interpretation separate from Maer's private intent."
|
||||
}
|
||||
],
|
||||
"branching": {
|
||||
"branch_action": "none",
|
||||
"active_branch_flags": [
|
||||
"cold_wake_claimant_status_unresolved"
|
||||
],
|
||||
"event_constraints": [
|
||||
{
|
||||
"constraint_id": "constraint.personhood_unresolved",
|
||||
"constraint_type": "branch_local_event",
|
||||
"summary": "The packet may represent a claimant, but this beat must not prove or disprove personhood.",
|
||||
"pull_strength": "locked"
|
||||
}
|
||||
],
|
||||
"sibling_exclusion_notes": []
|
||||
},
|
||||
"item_manifest_deltas": [],
|
||||
"unresolved_hooks": [
|
||||
{
|
||||
"hook_id": "hook.packet_personhood",
|
||||
"hook_type": "story",
|
||||
"summary": "Whether the corrupted packet represents a person remains unresolved.",
|
||||
"owner": "coordinator",
|
||||
"status": "carried"
|
||||
},
|
||||
{
|
||||
"hook_id": "hook.sanctuary_capacity",
|
||||
"hook_type": "world_state",
|
||||
"summary": "The sanctuary's capacity and ledger backing remain future pressure surfaces.",
|
||||
"owner": "coordinator",
|
||||
"status": "carried"
|
||||
}
|
||||
],
|
||||
"review": {
|
||||
"reviewer": "Codex",
|
||||
"review_notes": [
|
||||
"This is a backfilled accepted-as-draft example for schema shakedown, not gold responder data.",
|
||||
"It demonstrates the coordinator artifact shape and preserves the sandbox caveat around older Qwen captures."
|
||||
],
|
||||
"accepted_for_training": true,
|
||||
"failure_labels": []
|
||||
}
|
||||
}
|
||||
|
|
@ -55,6 +55,11 @@ Ghostlight now has the persistence spine plus the first architecture payload:
|
|||
- `examples/lore-grounding/historical-flashpoint.template.json`
|
||||
- `examples/lore-grounding/cold-wake-panic.ganymede-corridor.json`
|
||||
- `tools/validate_lore_grounding.py`
|
||||
- coordinator artifact seam:
|
||||
- `schemas/coordinator-artifact.schema.json`
|
||||
- `examples/coordinator/cold-wake-sanctuary-intake.v0.json`
|
||||
- `tools/validate_coordinator_artifacts.py`
|
||||
- `npm run coordinator:validate`
|
||||
- Cold Wake story-lab seam:
|
||||
- `docs/experiments/cold-wake-story-lab.md`
|
||||
- `examples/agent-state.cold-wake-story-lab.json`
|
||||
|
|
@ -151,6 +156,12 @@ targets. They exist to expose missing fields, bad boundaries, leakage risks, and
|
|||
validator gaps before large data generation. Robust organs will need roughly an
|
||||
order of magnitude more examples, with separate review-assistant and runtime
|
||||
targets.
|
||||
The first coordinator artifact seam now exists. It captures scene setup,
|
||||
next-beat choice, acting-agent choice, machinery invocation plan, sandboxed
|
||||
responder handoffs, world-state refs, proposed deltas, branch constraints,
|
||||
item-manifest deltas, unresolved hooks, glue prose, and review status. The first
|
||||
example is a backfilled Cold Wake sanctuary packet-assessment artifact accepted
|
||||
as draft for schema shakedown, not gold responder data.
|
||||
It now uses three timeline lanes: `historical_grounded`,
|
||||
`transition_grounded`, and `future_branch`. Future branches are required
|
||||
training/evaluation material for post-Rupture Elysium concepts, but generated
|
||||
|
|
@ -179,10 +190,11 @@ narrow elaboration before treating the detail as available to Ghostlight.
|
|||
|
||||
## Current Next Action
|
||||
|
||||
Define the coordinator artifact schema so future story passes capture
|
||||
next-beat choice, glue prose, world-state refs, branch flags, unresolved hooks,
|
||||
and machinery invocations as trainable data, then return to the Sella
|
||||
prompt/rendering fix.
|
||||
Use the coordinator artifact schema for the next fresh generation pass: produce
|
||||
a source-grounded coordinator receipt first, then generate any responder turn
|
||||
through a sandboxed packet-only worker and preserve raw output, reviewed output,
|
||||
hidden-context refs, leakage audit, and coordinator repair labels. Do not call
|
||||
Qwen for gold responder data yet.
|
||||
|
||||
Cat/Oz remains useful as an Elysium procedural mechanics fixture, but
|
||||
single-history grounding should start from authored historical lore rather than
|
||||
|
|
|
|||
|
|
@ -111,6 +111,11 @@ state and re-entry discipline.
|
|||
factional pressure fields
|
||||
- `schemas/projected-local-context.schema.json`
|
||||
- v0 contract for projected character-local operating context artifacts
|
||||
- `schemas/coordinator-artifact.schema.json`
|
||||
- v0 contract for coordinator/story-runtime receipts: scene setup,
|
||||
next-beat choice, acting-agent choice, machinery invocations, sandboxed
|
||||
responder handoffs, world-state refs, proposed deltas, branch constraints,
|
||||
item-manifest deltas, unresolved hooks, glue prose, and review notes
|
||||
- `schemas/agent-state.required-fields.json`
|
||||
- required first-class variable names for canonical state and relationship
|
||||
stance
|
||||
|
|
@ -125,6 +130,10 @@ state and re-entry discipline.
|
|||
- `examples/projections/cold-wake-story-lab.jsonl`
|
||||
- response-turn projection examples for the Cold Wake story lab, including
|
||||
rejected and accepted Maer/Veyr prompt revisions
|
||||
- `examples/coordinator/cold-wake-sanctuary-intake.v0.json`
|
||||
- first coordinator artifact schema-shakedown example, backfilled from the
|
||||
accepted-as-draft sanctuary packet-assessment beat and explicitly marked as
|
||||
not gold responder data
|
||||
- `experiments/cold-wake-story-lab/`
|
||||
- Qwen response captures and reviews from the writing experiment
|
||||
- `the-narrowest-possible-margin.md`, the first readable short story
|
||||
|
|
@ -253,6 +262,10 @@ state and re-entry discipline.
|
|||
- `tools/validate_projected_contexts.py`
|
||||
- validates projected context artifacts and rejects prompt text that leaks raw
|
||||
canonical state internals
|
||||
- `tools/validate_coordinator_artifacts.py`
|
||||
- validates v0 coordinator artifacts, including sandboxed responder handoff
|
||||
fields, world-state refs, branch constraints, proposed deltas, unresolved
|
||||
hooks, and review status
|
||||
- `tools/apply_sequential_ink_branch_mutation.py`
|
||||
- applies a reviewed replay of one selected branch into a mutated agent-state
|
||||
fixture and mutation receipt without letting Ink variables become
|
||||
|
|
@ -274,8 +287,9 @@ state and re-entry discipline.
|
|||
- automatic promotion of Ink branch outcomes into canonical state
|
||||
|
||||
The canonical agent-state schema, projection example schema, lore grounding
|
||||
digest schema, projected-local-context schema, first draft Cold Wake grounding
|
||||
digest, and first Cold Wake story-lab Qwen captures now exist as v0 seams. The
|
||||
digest schema, projected-local-context schema, coordinator artifact schema,
|
||||
first draft Cold Wake grounding digest, and first Cold Wake story-lab Qwen
|
||||
captures now exist as v0 seams. The
|
||||
first complete Cold Wake story pass exists with receipts, projection controls
|
||||
have been promoted, and Ink is now the standard branching scene format. The
|
||||
first Qwen-generated Ink draft now exists with a reviewed capture, the first
|
||||
|
|
@ -310,7 +324,9 @@ and deterministic code for gates. The listed per-stage counts are pilot
|
|||
schema-shakedown gates, not robust training targets; review-assistant and runtime
|
||||
targets are larger corpus tiers meant to avoid declaring victory after the first
|
||||
small pile of sacrificial data merely shows where the schema is wrong. The
|
||||
coordinator is currently the authoring
|
||||
first coordinator artifact seam now validates through `npm run schema:validate`
|
||||
and backfills the sanctuary packet-assessment beat as an accepted-as-draft
|
||||
schema shakedown example. The coordinator is currently the authoring
|
||||
agent: it glues scenes together, carries world-state refs and unresolved hooks,
|
||||
decides which machinery runs, and emits glue prose. That output should stay
|
||||
game-engine-shaped even while the prose lives in model imagination. The
|
||||
|
|
|
|||
|
|
@ -324,6 +324,14 @@
|
|||
- Coordinator artifacts should be able to attach item-manifest deltas when a
|
||||
scene or branch decision discovers, alters, upgrades, restricts, salvages,
|
||||
counterfeits, or economically stresses a technology or item.
|
||||
- First schema seam: `schemas/coordinator-artifact.schema.json`,
|
||||
`examples/coordinator/cold-wake-sanctuary-intake.v0.json`, and
|
||||
`tools/validate_coordinator_artifacts.py` now validate the coordinator
|
||||
receipt shape through `npm run schema:validate`.
|
||||
- Next prototype: use the coordinator artifact before generating fresh story
|
||||
or lore elaboration. The coordinator must write the receipt first, then any
|
||||
responder turn must be generated through a sandboxed packet-only worker and
|
||||
reviewed into the artifact rather than improvised into chat.
|
||||
|
||||
7. Build the first drama-scaffolding loop.
|
||||
- memory updates
|
||||
|
|
|
|||
|
|
@ -7,10 +7,11 @@
|
|||
"state:status": "\"C:\\Users\\Meta\\.cache\\codex-runtimes\\codex-primary-runtime\\dependencies\\python\\python.exe\" .\\tools\\ghostlight_state.py status",
|
||||
"state:prepare-compaction": "\"C:\\Users\\Meta\\.cache\\codex-runtimes\\codex-primary-runtime\\dependencies\\python\\python.exe\" .\\tools\\ghostlight_prepare_compaction.py",
|
||||
"agent-state:validate": "\"C:\\Users\\Meta\\.cache\\codex-runtimes\\codex-primary-runtime\\dependencies\\python\\python.exe\" .\\tools\\validate_agent_state.py",
|
||||
"schema:validate": "npm run agent-state:validate && npm run projection:validate && npm run projected-context:validate && npm run lore-grounding:validate && npm run qwen-captures:validate && npm run ink:validate",
|
||||
"schema:validate": "npm run agent-state:validate && npm run projection:validate && npm run projected-context:validate && npm run lore-grounding:validate && npm run coordinator:validate && npm run qwen-captures:validate && npm run ink:validate",
|
||||
"projection:validate": "\"C:\\Users\\Meta\\.cache\\codex-runtimes\\codex-primary-runtime\\dependencies\\python\\python.exe\" .\\tools\\validate_projection_examples.py",
|
||||
"projected-context:validate": "\"C:\\Users\\Meta\\.cache\\codex-runtimes\\codex-primary-runtime\\dependencies\\python\\python.exe\" .\\tools\\validate_projected_contexts.py",
|
||||
"lore-grounding:validate": "\"C:\\Users\\Meta\\.cache\\codex-runtimes\\codex-primary-runtime\\dependencies\\python\\python.exe\" .\\tools\\validate_lore_grounding.py",
|
||||
"coordinator:validate": "\"C:\\Users\\Meta\\.cache\\codex-runtimes\\codex-primary-runtime\\dependencies\\python\\python.exe\" .\\tools\\validate_coordinator_artifacts.py",
|
||||
"qwen-captures:validate": "\"C:\\Users\\Meta\\.cache\\codex-runtimes\\codex-primary-runtime\\dependencies\\python\\python.exe\" .\\tools\\validate_qwen_captures.py",
|
||||
"ink:validate": "\"C:\\Users\\Meta\\.cache\\codex-runtimes\\codex-primary-runtime\\dependencies\\python\\python.exe\" .\\tools\\validate_ink_examples.py",
|
||||
"qwen:check-tools": "\"C:\\Users\\Meta\\.cache\\codex-runtimes\\codex-primary-runtime\\dependencies\\python\\python.exe\" .\\tools\\check_qwen_chat_tools.py"
|
||||
|
|
|
|||
858
schemas/coordinator-artifact.schema.json
Normal file
858
schemas/coordinator-artifact.schema.json
Normal file
|
|
@ -0,0 +1,858 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://github.com/GameCult/Ghostlight/schemas/coordinator-artifact.schema.json",
|
||||
"title": "Ghostlight Coordinator Artifact Schema",
|
||||
"description": "Reviewed artifact for coordinator/story-runtime decisions, scene glue, machinery invocations, world-state refs, branch flags, unresolved hooks, sandboxed responder handoffs, and proposed deltas.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"schema_version",
|
||||
"artifact_id",
|
||||
"review_status",
|
||||
"fixture_lane",
|
||||
"canon_status",
|
||||
"source_refs",
|
||||
"input_refs",
|
||||
"scene_context",
|
||||
"coordinator_decision",
|
||||
"machinery_plan",
|
||||
"world_state_refs",
|
||||
"proposed_deltas",
|
||||
"branching",
|
||||
"unresolved_hooks",
|
||||
"review"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"schema_version": {
|
||||
"const": "ghostlight.coordinator_artifact.v0"
|
||||
},
|
||||
"artifact_id": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"review_status": {
|
||||
"$ref": "#/$defs/review_status"
|
||||
},
|
||||
"fixture_lane": {
|
||||
"enum": [
|
||||
"historical_grounded",
|
||||
"transition_grounded",
|
||||
"future_branch"
|
||||
]
|
||||
},
|
||||
"canon_status": {
|
||||
"enum": [
|
||||
"single_history",
|
||||
"branch_local",
|
||||
"promoted_branch",
|
||||
"template",
|
||||
"draft"
|
||||
]
|
||||
},
|
||||
"source_refs": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"$ref": "#/$defs/source_ref"
|
||||
}
|
||||
},
|
||||
"input_refs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"agent_state_ref",
|
||||
"lore_grounding_refs"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"agent_state_ref": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"lore_grounding_refs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"prior_artifact_refs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"projected_context_refs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"ink_refs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"item_manifest_refs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"scene_context": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"scene_id",
|
||||
"sequence_marker",
|
||||
"location_id",
|
||||
"participant_ids",
|
||||
"active_object_ids",
|
||||
"public_facts",
|
||||
"scene_pressure"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"scene_id": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"sequence_marker": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"location_id": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"participant_ids": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"active_object_ids": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"active_resource_ids": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"public_facts": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"$ref": "#/$defs/text_with_refs"
|
||||
}
|
||||
},
|
||||
"scene_pressure": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"$ref": "#/$defs/text_with_refs"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"coordinator_decision": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"decision_id",
|
||||
"selected_next_beat",
|
||||
"selected_acting_agent_id",
|
||||
"rationale",
|
||||
"glue_prose",
|
||||
"glue_prose_status"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"decision_id": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"selected_next_beat": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"selected_acting_agent_id": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"candidate_next_beats": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/candidate_choice"
|
||||
}
|
||||
},
|
||||
"rationale": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"glue_prose": {
|
||||
"type": "string"
|
||||
},
|
||||
"glue_prose_status": {
|
||||
"enum": [
|
||||
"not_canonical",
|
||||
"accepted_as_narration",
|
||||
"needs_revision",
|
||||
"rejected"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"machinery_plan": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"invocations"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"invocations": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/invocation"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sandboxed_responder_handoffs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/sandbox_handoff"
|
||||
}
|
||||
},
|
||||
"world_state_refs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"read_refs",
|
||||
"write_candidate_refs"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"read_refs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/state_ref"
|
||||
}
|
||||
},
|
||||
"write_candidate_refs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/state_ref"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"proposed_deltas": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/proposed_delta"
|
||||
}
|
||||
},
|
||||
"branching": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"branch_action",
|
||||
"active_branch_flags",
|
||||
"event_constraints"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"branch_action": {
|
||||
"enum": [
|
||||
"none",
|
||||
"continue_branch",
|
||||
"split_branch",
|
||||
"merge_branch",
|
||||
"promote_branch_fact"
|
||||
]
|
||||
},
|
||||
"branch_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"branch_lineage": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"active_branch_flags": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"event_constraints": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/event_constraint"
|
||||
}
|
||||
},
|
||||
"sibling_exclusion_notes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"item_manifest_deltas": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/item_manifest_delta"
|
||||
}
|
||||
},
|
||||
"unresolved_hooks": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/unresolved_hook"
|
||||
}
|
||||
},
|
||||
"review": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"reviewer",
|
||||
"review_notes",
|
||||
"accepted_for_training",
|
||||
"failure_labels"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"reviewer": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"review_notes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"accepted_for_training": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"failure_labels": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"$defs": {
|
||||
"review_status": {
|
||||
"enum": [
|
||||
"draft",
|
||||
"accepted",
|
||||
"accepted_as_draft",
|
||||
"useful_needs_revision",
|
||||
"rejected",
|
||||
"superseded"
|
||||
]
|
||||
},
|
||||
"source_ref": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ref_id",
|
||||
"path",
|
||||
"purpose"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"ref_id": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"path": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"purpose": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"text_with_refs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"text",
|
||||
"refs"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"text": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"refs": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"candidate_choice": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"choice_id",
|
||||
"summary",
|
||||
"status"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"choice_id": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"summary": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"status": {
|
||||
"enum": [
|
||||
"selected",
|
||||
"rejected",
|
||||
"deferred"
|
||||
]
|
||||
},
|
||||
"reason": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"invocation": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"invocation_id",
|
||||
"organ",
|
||||
"purpose",
|
||||
"status"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"invocation_id": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"organ": {
|
||||
"enum": [
|
||||
"lore_grounding_compiler",
|
||||
"memory_lore_retriever",
|
||||
"projector",
|
||||
"sandboxed_responder",
|
||||
"event_resolver",
|
||||
"participant_appraiser",
|
||||
"state_mutator",
|
||||
"relationship_perception_updater",
|
||||
"output_evaluator",
|
||||
"item_manifest_generator",
|
||||
"institution_faction_consumer_model",
|
||||
"human_review",
|
||||
"other"
|
||||
]
|
||||
},
|
||||
"purpose": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"input_refs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"output_refs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"$ref": "#/$defs/review_status"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sandbox_handoff": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"handoff_id",
|
||||
"responder_agent_id",
|
||||
"projected_context_ref",
|
||||
"visible_input_ref",
|
||||
"hidden_context_refs",
|
||||
"isolation_method",
|
||||
"raw_output_ref",
|
||||
"reviewed_output_ref",
|
||||
"coordinator_interventions",
|
||||
"leakage_audit"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"handoff_id": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"responder_agent_id": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"projected_context_ref": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"visible_input_ref": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"hidden_context_refs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"isolation_method": {
|
||||
"enum": [
|
||||
"subagent_no_fork",
|
||||
"manual_packet_only",
|
||||
"external_model_packet_only",
|
||||
"not_sandboxed"
|
||||
]
|
||||
},
|
||||
"raw_output_ref": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"reviewed_output_ref": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"coordinator_interventions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/coordinator_intervention"
|
||||
}
|
||||
},
|
||||
"leakage_audit": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"private_state_leak",
|
||||
"author_only_leak",
|
||||
"future_branch_leak",
|
||||
"raw_state_soup",
|
||||
"prompt_parroting",
|
||||
"body_or_object_omniscience"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"private_state_leak": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"author_only_leak": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"future_branch_leak": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"raw_state_soup": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"prompt_parroting": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"body_or_object_omniscience": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"notes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"coordinator_intervention": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"intervention_type",
|
||||
"description"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"intervention_type": {
|
||||
"enum": [
|
||||
"none",
|
||||
"normalization",
|
||||
"schema_repair",
|
||||
"prose_edit",
|
||||
"lore_correction",
|
||||
"leakage_removal",
|
||||
"rejection"
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"state_ref": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ref_id",
|
||||
"ref_type",
|
||||
"path"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"ref_id": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"ref_type": {
|
||||
"enum": [
|
||||
"agent",
|
||||
"relationship",
|
||||
"scene",
|
||||
"event",
|
||||
"object",
|
||||
"resource",
|
||||
"branch",
|
||||
"item_manifest",
|
||||
"world_fact",
|
||||
"memory",
|
||||
"other"
|
||||
]
|
||||
},
|
||||
"path": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"visibility": {
|
||||
"enum": [
|
||||
"public",
|
||||
"character_local",
|
||||
"coordinator_only",
|
||||
"author_only"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"proposed_delta": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"delta_id",
|
||||
"delta_type",
|
||||
"target_ref",
|
||||
"summary",
|
||||
"authority",
|
||||
"status"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"delta_id": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"delta_type": {
|
||||
"enum": [
|
||||
"memory_write",
|
||||
"relationship_update",
|
||||
"perceived_overlay_update",
|
||||
"world_fact_update",
|
||||
"object_state_update",
|
||||
"resource_delta",
|
||||
"branch_flag_update",
|
||||
"item_manifest_delta",
|
||||
"no_delta"
|
||||
]
|
||||
},
|
||||
"target_ref": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"summary": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"authority": {
|
||||
"enum": [
|
||||
"deterministic_gate",
|
||||
"manual_review",
|
||||
"coordinator_proposal",
|
||||
"blocked"
|
||||
]
|
||||
},
|
||||
"status": {
|
||||
"enum": [
|
||||
"proposed",
|
||||
"accepted",
|
||||
"rejected",
|
||||
"deferred",
|
||||
"blocked"
|
||||
]
|
||||
},
|
||||
"rationale": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"event_constraint": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"constraint_id",
|
||||
"constraint_type",
|
||||
"summary"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"constraint_id": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"constraint_type": {
|
||||
"enum": [
|
||||
"branch_attractor",
|
||||
"fated_event",
|
||||
"tech_order_constraint",
|
||||
"quest_injection",
|
||||
"branch_local_event"
|
||||
]
|
||||
},
|
||||
"summary": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"pull_strength": {
|
||||
"enum": [
|
||||
"weak",
|
||||
"medium",
|
||||
"strong",
|
||||
"locked"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"item_manifest_delta": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"delta_id",
|
||||
"delta_type",
|
||||
"summary",
|
||||
"target_class",
|
||||
"status"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"delta_id": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"delta_type": {
|
||||
"enum": [
|
||||
"blueprint_candidate",
|
||||
"instance_provenance_candidate",
|
||||
"faction_tech_base_delta",
|
||||
"supply_chain_delta",
|
||||
"engine_schema_gap",
|
||||
"source_gap",
|
||||
"rejected_design"
|
||||
]
|
||||
},
|
||||
"summary": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"target_class": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"artifact_ref": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"enum": [
|
||||
"proposed",
|
||||
"accepted",
|
||||
"rejected",
|
||||
"deferred"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"unresolved_hook": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"hook_id",
|
||||
"hook_type",
|
||||
"summary",
|
||||
"owner",
|
||||
"status"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"hook_id": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"hook_type": {
|
||||
"enum": [
|
||||
"story",
|
||||
"relationship",
|
||||
"world_state",
|
||||
"branch",
|
||||
"item_manifest",
|
||||
"lore_gap",
|
||||
"schema_gap",
|
||||
"review"
|
||||
]
|
||||
},
|
||||
"summary": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"owner": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"status": {
|
||||
"enum": [
|
||||
"open",
|
||||
"carried",
|
||||
"resolved",
|
||||
"deferred",
|
||||
"blocked"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -59,3 +59,4 @@
|
|||
{"ts": "2026-05-02T08:51:57+00:00", "type": "architecture", "status": "ok", "note": "Documented the player-facing gear fantasy and content-refinery framing: ultimate items should be provenance hunts through blueprint, assembly quality, manufacturer practice, supply-chain lineage, repair history, counterfeit substitution, and operating conditions; Ghostlight should convert lore-grounded ideas into reviewed database-shaped Aetheria-Economy candidates rather than another manual spreadsheet bottleneck."}
|
||||
{"ts": "2026-05-02T09:04:24+00:00", "type": "architecture", "status": "ok", "note": "Accepted sandboxed responder-data doctrine: coordinator may be omniscient, but gold responder examples must be generated from only the exact projected local packet, visible event, allowed actions, and explicitly included source excerpts. Artifacts must preserve raw output, reviewed output, hidden-context refs, leakage audit, isolation method, and coordinator intervention labels so repaired prose is not laundered as raw responder behavior."}
|
||||
{"ts": "2026-05-02T09:08:43+00:00", "type": "architecture", "status": "ok", "note": "Clarified training corpus scale: the existing per-stage sample counts are pilot schema-shakedown gates for exposing schema, boundary, leakage, validator, and workflow problems, not robust training targets. Review-assistant and runtime targets require much larger corpora, held-out evaluation, negative coverage, and failure audits; pilot data may be invalidated by schema fixes."}
|
||||
{"ts": "2026-05-02T09:14:24+00:00", "type": "implementation", "status": "ok", "note": "Added the v0 coordinator artifact seam: schemas/coordinator-artifact.schema.json, examples/coordinator/cold-wake-sanctuary-intake.v0.json, tools/validate_coordinator_artifacts.py, and npm run coordinator:validate. The schema captures scene setup, next-beat choice, machinery invocations, sandboxed responder handoffs, world-state refs, proposed deltas, branch constraints, item-manifest deltas, unresolved hooks, glue prose, and review status."}
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ accepted_design:
|
|||
- The soft organs are training targets: coordinator/story runtime, projector, character agent/responder, appraiser, state mutator, relationship/perception classifier, Aetheria responder, and later institution/faction/consumer decision models should all produce reviewed artifacts for future distillation or fine-tuning.
|
||||
- An Aetheria-tuned responder should learn lore, tone, factional preconceptions, species affordances, and institutional pressure from strong source-grounded responses spread throughout the timeline, but it still acts only inside Ghostlight's character-local context, deterministic gates, and mutation authority.
|
||||
- The coordinator is a trainable artifact: it glues scenes together, chooses next beats and acting agents, invokes specialist machinery, carries unresolved hooks, emits reviewed glue prose, and proposes world-state changes without bypassing deterministic gates.
|
||||
- Coordinator artifacts use `ghostlight.coordinator_artifact.v0` to capture scene setup, next-beat choice, acting-agent choice, machinery invocations, sandboxed responder handoffs, world-state refs, proposed deltas, branch constraints, item-manifest deltas, unresolved hooks, glue prose, and review status.
|
||||
- The concrete training plan enumerates the trainable stages and their model families: generative decoder LLMs for coordinator/responder/soft structured outputs, classifiers or cross-encoders for appraisal/evaluation/relationship movement, retrieval models for memory and lore selection, and deterministic code for gates.
|
||||
- Training-plan sample counts are pilot schema-shakedown gates, not robust corpus targets; pilot data may be invalidated by schema fixes, while review-assistant and runtime targets are expected to be roughly an order of magnitude larger with held-out evaluation and failure audits.
|
||||
- The timeline training plan now requires future-branch Elysium examples so the responder, coordinator, appraiser, and decision models learn post-Rupture concepts such as Aether, pseudospace, temporal nonlinearity, spirits, necrotech, mutable bodies, altered substrates, and weird institutions under branch-lineage labels.
|
||||
|
|
@ -162,5 +163,5 @@ accepted_design:
|
|||
- Ghostlight's technology pipeline should function as a content refinery: ground ideas in lore and mechanics, decompose them into parts and supply chains, map them to Aetheria-Economy blueprint classes, define performance and instance variation, preserve review labels, and produce database-shaped candidates instead of spreadsheet sludge.
|
||||
|
||||
current_status:
|
||||
summary: Ghostlight now has the Epiphany-style persistence spine, the first architecture payload, the v0 canonical agent-state schema seam, prompt projection docs, immediate schema fixes from evaluation, first reviewed Cat/Oz projection examples, a revised Aetheria lore-grounding architecture, a lore grounding digest schema, the first draft Cold Wake historical grounding digest, a Cold Wake story-lab fixture, projection controls, validated Qwen capture receipts, a complete Cold Wake short story assembled from accepted projection outputs, a hand-authored Ink-backed Cold Wake branching scene, the first Qwen-generated Ink draft materialized from local awareness with reviewed training annotations, the first reviewed sequential branch mutation that updates both Maer and Sella after a sanctuary intake beat, a v2 sequential Qwen capture proving the symmetrical turn shape produces better action behavior, a v5 sequential Qwen capture proving local thinking-plus-tools invocation works for the scene runner, the first projected-local-context seam that routes sequential prompts through character-local operating prose instead of raw state variables, tightened receipt handling for projector-routed Qwen failures, a default no-thinking policy for strict sequential tool calls, a v10 no-thinking projector-routed capture accepted as draft, the first materialized projector-routed sequential Ink scene with reviewed mutation training data, a source-checked embodiment/interface projection surface for Navigator scenes, a formal source-first Aetheria generation doctrine, v11-v17 source-checked retry receipts showing improved Maer embodiment plus remaining Sella response/prompt-leak blockers, a soft-model training artifact doctrine, a concrete training plan with pilot schema-shakedown gates separated from robust corpus targets, sandboxed responder-data requirements, an explicit future-branch lane, Elysium branch event constraints, and a technology/item manifest plan for turning nebulous named tech into blueprint-grade components, assemblies, faction tech bases, supply chains, upgrade paths, gameplay hooks, provenance-hunting player fantasy, and content-refinery outputs mapped onto Aetheria-Economy's CultCache blueprint and instance model.
|
||||
next_action: Define the coordinator artifact schema so future story passes capture next-beat choice, glue prose, world-state refs, branch flags, unresolved hooks, and machinery invocations as trainable data, then return to the Sella prompt/rendering fix.
|
||||
summary: Ghostlight now has the Epiphany-style persistence spine, the first architecture payload, the v0 canonical agent-state schema seam, prompt projection docs, immediate schema fixes from evaluation, first reviewed Cat/Oz projection examples, a revised Aetheria lore-grounding architecture, a lore grounding digest schema, the first coordinator artifact schema seam, the first draft Cold Wake historical grounding digest, a Cold Wake story-lab fixture, projection controls, validated Qwen capture receipts, a complete Cold Wake short story assembled from accepted projection outputs, a hand-authored Ink-backed Cold Wake branching scene, the first Qwen-generated Ink draft materialized from local awareness with reviewed training annotations, the first reviewed sequential branch mutation that updates both Maer and Sella after a sanctuary intake beat, a v2 sequential Qwen capture proving the symmetrical turn shape produces better action behavior, a v5 sequential Qwen capture proving local thinking-plus-tools invocation works for the scene runner, the first projected-local-context seam that routes sequential prompts through character-local operating prose instead of raw state variables, tightened receipt handling for projector-routed Qwen failures, a default no-thinking policy for strict sequential tool calls, a v10 no-thinking projector-routed capture accepted as draft, the first materialized projector-routed sequential Ink scene with reviewed mutation training data, a source-checked embodiment/interface projection surface for Navigator scenes, a formal source-first Aetheria generation doctrine, v11-v17 source-checked retry receipts showing improved Maer embodiment plus remaining Sella response/prompt-leak blockers, a soft-model training artifact doctrine, a concrete training plan with pilot schema-shakedown gates separated from robust corpus targets, sandboxed responder-data requirements, an explicit future-branch lane, Elysium branch event constraints, and a technology/item manifest plan for turning nebulous named tech into blueprint-grade components, assemblies, faction tech bases, supply chains, upgrade paths, gameplay hooks, provenance-hunting player fantasy, and content-refinery outputs mapped onto Aetheria-Economy's CultCache blueprint and instance model.
|
||||
next_action: Use the coordinator artifact schema for the next fresh generation pass: produce a source-grounded coordinator receipt first, then generate any responder turn through a sandboxed packet-only worker and preserve raw output, reviewed output, hidden-context refs, leakage audit, and coordinator repair labels. Do not call Qwen for gold responder data yet.
|
||||
|
|
|
|||
299
tools/validate_coordinator_artifacts.py
Normal file
299
tools/validate_coordinator_artifacts.py
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
"""Validate Ghostlight coordinator artifacts.
|
||||
|
||||
This is a focused structural validator for the v0 coordinator seam. It checks
|
||||
the fields that matter before these artifacts become training data: scene refs,
|
||||
machinery calls, sandboxed responder handoffs, proposed deltas, branch flags,
|
||||
and review status.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
DEFAULT_ARTIFACTS = sorted((ROOT / "examples" / "coordinator").glob("*.json"))
|
||||
|
||||
REVIEW_STATUSES = {"draft", "accepted", "accepted_as_draft", "useful_needs_revision", "rejected", "superseded"}
|
||||
FIXTURE_LANES = {"historical_grounded", "transition_grounded", "future_branch"}
|
||||
CANON_STATUSES = {"single_history", "branch_local", "promoted_branch", "template", "draft"}
|
||||
ORGANS = {
|
||||
"lore_grounding_compiler",
|
||||
"memory_lore_retriever",
|
||||
"projector",
|
||||
"sandboxed_responder",
|
||||
"event_resolver",
|
||||
"participant_appraiser",
|
||||
"state_mutator",
|
||||
"relationship_perception_updater",
|
||||
"output_evaluator",
|
||||
"item_manifest_generator",
|
||||
"institution_faction_consumer_model",
|
||||
"human_review",
|
||||
"other",
|
||||
}
|
||||
BRANCH_ACTIONS = {"none", "continue_branch", "split_branch", "merge_branch", "promote_branch_fact"}
|
||||
EVENT_CONSTRAINT_TYPES = {"branch_attractor", "fated_event", "tech_order_constraint", "quest_injection", "branch_local_event"}
|
||||
ISOLATION_METHODS = {"subagent_no_fork", "manual_packet_only", "external_model_packet_only", "not_sandboxed"}
|
||||
DELTA_TYPES = {
|
||||
"memory_write",
|
||||
"relationship_update",
|
||||
"perceived_overlay_update",
|
||||
"world_fact_update",
|
||||
"object_state_update",
|
||||
"resource_delta",
|
||||
"branch_flag_update",
|
||||
"item_manifest_delta",
|
||||
"no_delta",
|
||||
}
|
||||
DELTA_AUTHORITIES = {"deterministic_gate", "manual_review", "coordinator_proposal", "blocked"}
|
||||
DELTA_STATUSES = {"proposed", "accepted", "rejected", "deferred", "blocked"}
|
||||
|
||||
|
||||
class ValidationError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def load_json(path: Path) -> Any:
|
||||
return json.loads(path.read_text(encoding="utf-8-sig"))
|
||||
|
||||
|
||||
def require(condition: bool, message: str) -> None:
|
||||
if not condition:
|
||||
raise ValidationError(message)
|
||||
|
||||
|
||||
def require_keys(obj: dict[str, Any], keys: list[str], path: str) -> None:
|
||||
missing = [key for key in keys if key not in obj]
|
||||
require(not missing, f"{path} missing required keys: {', '.join(missing)}")
|
||||
|
||||
|
||||
def require_string(value: Any, path: str) -> None:
|
||||
require(isinstance(value, str) and value.strip(), f"{path} must be a non-empty string")
|
||||
|
||||
|
||||
def require_string_array(value: Any, path: str, *, nonempty: bool = False) -> None:
|
||||
require(isinstance(value, list), f"{path} must be an array")
|
||||
require(not nonempty or bool(value), f"{path} must not be empty")
|
||||
for index, item in enumerate(value):
|
||||
require_string(item, f"{path}[{index}]")
|
||||
|
||||
|
||||
def validate_text_with_refs(value: Any, path: str) -> None:
|
||||
require(isinstance(value, dict), f"{path} must be an object")
|
||||
require_keys(value, ["text", "refs"], path)
|
||||
require_string(value["text"], f"{path}.text")
|
||||
require_string_array(value["refs"], f"{path}.refs", nonempty=True)
|
||||
|
||||
|
||||
def validate_source_ref(value: Any, path: str) -> None:
|
||||
require(isinstance(value, dict), f"{path} must be an object")
|
||||
require_keys(value, ["ref_id", "path", "purpose"], path)
|
||||
for key in ["ref_id", "path", "purpose"]:
|
||||
require_string(value[key], f"{path}.{key}")
|
||||
|
||||
|
||||
def validate_invocation(value: Any, path: str) -> None:
|
||||
require(isinstance(value, dict), f"{path} must be an object")
|
||||
require_keys(value, ["invocation_id", "organ", "purpose", "status"], path)
|
||||
require_string(value["invocation_id"], f"{path}.invocation_id")
|
||||
require(value["organ"] in ORGANS, f"{path}.organ is invalid: {value['organ']}")
|
||||
require_string(value["purpose"], f"{path}.purpose")
|
||||
require(value["status"] in REVIEW_STATUSES, f"{path}.status is invalid: {value['status']}")
|
||||
if "input_refs" in value:
|
||||
require_string_array(value["input_refs"], f"{path}.input_refs")
|
||||
if "output_refs" in value:
|
||||
require_string_array(value["output_refs"], f"{path}.output_refs")
|
||||
|
||||
|
||||
def validate_sandbox_handoff(value: Any, path: str) -> None:
|
||||
require(isinstance(value, dict), f"{path} must be an object")
|
||||
require_keys(
|
||||
value,
|
||||
[
|
||||
"handoff_id",
|
||||
"responder_agent_id",
|
||||
"projected_context_ref",
|
||||
"visible_input_ref",
|
||||
"hidden_context_refs",
|
||||
"isolation_method",
|
||||
"raw_output_ref",
|
||||
"reviewed_output_ref",
|
||||
"coordinator_interventions",
|
||||
"leakage_audit",
|
||||
],
|
||||
path,
|
||||
)
|
||||
for key in ["handoff_id", "responder_agent_id", "projected_context_ref", "visible_input_ref", "raw_output_ref", "reviewed_output_ref"]:
|
||||
require_string(value[key], f"{path}.{key}")
|
||||
require_string_array(value["hidden_context_refs"], f"{path}.hidden_context_refs")
|
||||
require(value["isolation_method"] in ISOLATION_METHODS, f"{path}.isolation_method is invalid")
|
||||
require(value["isolation_method"] != "not_sandboxed", f"{path}.isolation_method must not be not_sandboxed for training examples")
|
||||
|
||||
interventions = value["coordinator_interventions"]
|
||||
require(isinstance(interventions, list), f"{path}.coordinator_interventions must be an array")
|
||||
for index, intervention in enumerate(interventions):
|
||||
intervention_path = f"{path}.coordinator_interventions[{index}]"
|
||||
require_keys(intervention, ["intervention_type", "description"], intervention_path)
|
||||
require_string(intervention["description"], f"{intervention_path}.description")
|
||||
|
||||
audit = value["leakage_audit"]
|
||||
require_keys(
|
||||
audit,
|
||||
[
|
||||
"private_state_leak",
|
||||
"author_only_leak",
|
||||
"future_branch_leak",
|
||||
"raw_state_soup",
|
||||
"prompt_parroting",
|
||||
"body_or_object_omniscience",
|
||||
],
|
||||
f"{path}.leakage_audit",
|
||||
)
|
||||
for key in [
|
||||
"private_state_leak",
|
||||
"author_only_leak",
|
||||
"future_branch_leak",
|
||||
"raw_state_soup",
|
||||
"prompt_parroting",
|
||||
"body_or_object_omniscience",
|
||||
]:
|
||||
require(isinstance(audit[key], bool), f"{path}.leakage_audit.{key} must be boolean")
|
||||
if "notes" in audit:
|
||||
require_string_array(audit["notes"], f"{path}.leakage_audit.notes")
|
||||
|
||||
|
||||
def validate_state_ref(value: Any, path: str) -> None:
|
||||
require(isinstance(value, dict), f"{path} must be an object")
|
||||
require_keys(value, ["ref_id", "ref_type", "path"], path)
|
||||
for key in ["ref_id", "ref_type", "path"]:
|
||||
require_string(value[key], f"{path}.{key}")
|
||||
|
||||
|
||||
def validate_delta(value: Any, path: str) -> None:
|
||||
require(isinstance(value, dict), f"{path} must be an object")
|
||||
require_keys(value, ["delta_id", "delta_type", "target_ref", "summary", "authority", "status"], path)
|
||||
require_string(value["delta_id"], f"{path}.delta_id")
|
||||
require(value["delta_type"] in DELTA_TYPES, f"{path}.delta_type is invalid: {value['delta_type']}")
|
||||
require_string(value["target_ref"], f"{path}.target_ref")
|
||||
require_string(value["summary"], f"{path}.summary")
|
||||
require(value["authority"] in DELTA_AUTHORITIES, f"{path}.authority is invalid: {value['authority']}")
|
||||
require(value["status"] in DELTA_STATUSES, f"{path}.status is invalid: {value['status']}")
|
||||
|
||||
|
||||
def validate_artifact(document: dict[str, Any], source: Path) -> None:
|
||||
require(document.get("schema_version") == "ghostlight.coordinator_artifact.v0", f"{source}.schema_version is wrong")
|
||||
require_keys(
|
||||
document,
|
||||
[
|
||||
"artifact_id",
|
||||
"review_status",
|
||||
"fixture_lane",
|
||||
"canon_status",
|
||||
"source_refs",
|
||||
"input_refs",
|
||||
"scene_context",
|
||||
"coordinator_decision",
|
||||
"machinery_plan",
|
||||
"world_state_refs",
|
||||
"proposed_deltas",
|
||||
"branching",
|
||||
"unresolved_hooks",
|
||||
"review",
|
||||
],
|
||||
str(source),
|
||||
)
|
||||
require(document["review_status"] in REVIEW_STATUSES, f"{source}.review_status is invalid")
|
||||
require(document["fixture_lane"] in FIXTURE_LANES, f"{source}.fixture_lane is invalid")
|
||||
require(document["canon_status"] in CANON_STATUSES, f"{source}.canon_status is invalid")
|
||||
|
||||
require(isinstance(document["source_refs"], list) and document["source_refs"], f"{source}.source_refs must be non-empty")
|
||||
for index, ref in enumerate(document["source_refs"]):
|
||||
validate_source_ref(ref, f"{source}.source_refs[{index}]")
|
||||
|
||||
input_refs = document["input_refs"]
|
||||
require_keys(input_refs, ["agent_state_ref", "lore_grounding_refs"], f"{source}.input_refs")
|
||||
require((ROOT / input_refs["agent_state_ref"]).exists(), f"{source}.input_refs.agent_state_ref does not exist")
|
||||
require_string_array(input_refs["lore_grounding_refs"], f"{source}.input_refs.lore_grounding_refs")
|
||||
for ref in input_refs["lore_grounding_refs"]:
|
||||
require((ROOT / ref).exists(), f"{source}.input_refs.lore_grounding_refs missing file: {ref}")
|
||||
|
||||
scene = document["scene_context"]
|
||||
require_keys(scene, ["scene_id", "sequence_marker", "location_id", "participant_ids", "active_object_ids", "public_facts", "scene_pressure"], f"{source}.scene_context")
|
||||
for key in ["scene_id", "sequence_marker", "location_id"]:
|
||||
require_string(scene[key], f"{source}.scene_context.{key}")
|
||||
require_string_array(scene["participant_ids"], f"{source}.scene_context.participant_ids", nonempty=True)
|
||||
require_string_array(scene["active_object_ids"], f"{source}.scene_context.active_object_ids")
|
||||
for key in ["public_facts", "scene_pressure"]:
|
||||
require(isinstance(scene[key], list) and scene[key], f"{source}.scene_context.{key} must be non-empty")
|
||||
for index, item in enumerate(scene[key]):
|
||||
validate_text_with_refs(item, f"{source}.scene_context.{key}[{index}]")
|
||||
|
||||
decision = document["coordinator_decision"]
|
||||
require_keys(decision, ["decision_id", "selected_next_beat", "selected_acting_agent_id", "rationale", "glue_prose", "glue_prose_status"], f"{source}.coordinator_decision")
|
||||
for key in ["decision_id", "selected_next_beat", "selected_acting_agent_id", "rationale"]:
|
||||
require_string(decision[key], f"{source}.coordinator_decision.{key}")
|
||||
require(decision["glue_prose_status"] in {"not_canonical", "accepted_as_narration", "needs_revision", "rejected"}, f"{source}.coordinator_decision.glue_prose_status is invalid")
|
||||
|
||||
invocations = document["machinery_plan"].get("invocations")
|
||||
require(isinstance(invocations, list), f"{source}.machinery_plan.invocations must be an array")
|
||||
for index, invocation in enumerate(invocations):
|
||||
validate_invocation(invocation, f"{source}.machinery_plan.invocations[{index}]")
|
||||
|
||||
for index, handoff in enumerate(document.get("sandboxed_responder_handoffs", [])):
|
||||
validate_sandbox_handoff(handoff, f"{source}.sandboxed_responder_handoffs[{index}]")
|
||||
|
||||
world_refs = document["world_state_refs"]
|
||||
require_keys(world_refs, ["read_refs", "write_candidate_refs"], f"{source}.world_state_refs")
|
||||
for key in ["read_refs", "write_candidate_refs"]:
|
||||
require(isinstance(world_refs[key], list), f"{source}.world_state_refs.{key} must be an array")
|
||||
for index, ref in enumerate(world_refs[key]):
|
||||
validate_state_ref(ref, f"{source}.world_state_refs.{key}[{index}]")
|
||||
|
||||
for index, delta in enumerate(document["proposed_deltas"]):
|
||||
validate_delta(delta, f"{source}.proposed_deltas[{index}]")
|
||||
|
||||
branching = document["branching"]
|
||||
require_keys(branching, ["branch_action", "active_branch_flags", "event_constraints"], f"{source}.branching")
|
||||
require(branching["branch_action"] in BRANCH_ACTIONS, f"{source}.branching.branch_action is invalid")
|
||||
require_string_array(branching["active_branch_flags"], f"{source}.branching.active_branch_flags")
|
||||
require(isinstance(branching["event_constraints"], list), f"{source}.branching.event_constraints must be an array")
|
||||
for index, constraint in enumerate(branching["event_constraints"]):
|
||||
constraint_path = f"{source}.branching.event_constraints[{index}]"
|
||||
require_keys(constraint, ["constraint_id", "constraint_type", "summary"], constraint_path)
|
||||
require(constraint["constraint_type"] in EVENT_CONSTRAINT_TYPES, f"{constraint_path}.constraint_type is invalid")
|
||||
require_string(constraint["summary"], f"{constraint_path}.summary")
|
||||
|
||||
require(isinstance(document["unresolved_hooks"], list), f"{source}.unresolved_hooks must be an array")
|
||||
for index, hook in enumerate(document["unresolved_hooks"]):
|
||||
hook_path = f"{source}.unresolved_hooks[{index}]"
|
||||
require_keys(hook, ["hook_id", "hook_type", "summary", "owner", "status"], hook_path)
|
||||
for key in ["hook_id", "hook_type", "summary", "owner", "status"]:
|
||||
require_string(hook[key], f"{hook_path}.{key}")
|
||||
|
||||
review = document["review"]
|
||||
require_keys(review, ["reviewer", "review_notes", "accepted_for_training", "failure_labels"], f"{source}.review")
|
||||
require_string(review["reviewer"], f"{source}.review.reviewer")
|
||||
require_string_array(review["review_notes"], f"{source}.review.review_notes")
|
||||
require(isinstance(review["accepted_for_training"], bool), f"{source}.review.accepted_for_training must be boolean")
|
||||
require_string_array(review["failure_labels"], f"{source}.review.failure_labels")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Validate Ghostlight coordinator artifacts.")
|
||||
parser.add_argument("paths", nargs="*", type=Path, help="Coordinator artifact JSON files to validate.")
|
||||
args = parser.parse_args()
|
||||
|
||||
paths = args.paths or DEFAULT_ARTIFACTS
|
||||
require(paths, "no coordinator artifacts found")
|
||||
for path in paths:
|
||||
validate_artifact(load_json(path), path)
|
||||
print(f"ok: {path}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Loading…
Reference in a new issue