Repository navigation
Conversation
doublewhy
force-pushed
the
307-participant-episode-surface
branch
from
October 9, 2026 11:23
0decfe7 to
fa88b95
Compare
11 tasks done
…ifications Add the optional behavior_specifications.*.episode_policy record (DSL-120): initialization precondition assertions, decision-epoch turn structure, completion and timeout terminal conditions, truncation conditions, and a reset policy with admitted control actions and a participant-memory scope. Every condition maps to exactly one ADR-013 terminal reason and names the evidence requirements that back the transition; interruption is never authored. The closed record rejects realized episode coordinates by name. Validate references, assertion roles, owner-bound timeouts and evidence fail closed, rewrite references under module composition, and compile each policy to participant.episode-policy.<name> keyed to the selected participants' participant.behavior.<agent> addresses. Regenerate the five scenario schemas with their publication entries, add the reference-catalog rows, valid and invalid fixtures, normative and explain documentation, lineage notes and DSL-120 traceability.
doublewhy
force-pushed
the
307-participant-episode-surface
branch
from
October 9, 2026 13:00
fa88b95 to
cbf38ee
Compare
doublewhy
marked this pull request as ready for review
October 9, 2026 15:43
This was referenced Oct 9, 2026
…nct from completion
Resolve reset_policy.memory_reset_authority_ref to exactly one declared
targetable SDL element during semantic validation. Dangling and ambiguous
refs fail closed, and ${var} refs wait for the post-instantiation pass.
Module composition now namespaces the authority. Compilation records the
element's canonical sdl.* address as memory_reset_authority_address, adds
it to the policy's refresh dependencies, and re-asserts that only an
episode_local_reset scope names one. Add the matching reference-catalog
row.
Reject a truncation condition that reuses the exact assertion set of a
completion condition, so one evidenced fact cannot end an episode as both
completed and truncated.
Reword the reset-policy comment, the normative section and the explain
guide: the ADR-095 assurance and information-state contracts require the
same pairing, but the policy does not supply their values. State that a
condition holds only when every assertion it names holds and that
validation checks only that its evidence requirements are declared, and
point the public participant-control guide at the episode policy fixture.
doublewhy
force-pushed
the
307-participant-episode-surface
branch
from
October 10, 2026 14:21
cbf38ee to
a621809
Compare
This was referenced Oct 11, 2026
doublewhy
marked this pull request as draft
October 12, 2026 22:42
This was referenced Oct 13, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
DSL-120 asks the SDL to support authored participant episode structure: initialization, turn or interaction structure, termination conditions, truncation conditions, and reset-related declarations. The #122 design (
specs/formal/participant-episode-model/README.md, matrix row "Authored episode policy is intent (EBM-01)") and ADR-013's 2026-08-02 amendment fix the shape. It is one typed, versioned episode-policy record on the existing behavior specification, built only from existing closed references. That includesreset_policy.memory_reset_authority_ref, which must resolve to exactly one declared SDL element, because the #122 preflight resolves the reset authority before compilation and fails closed. The record declares intent and compiles toparticipant.episode-policy.<name>beside the ADR-013 episode addresses. This PR implements that row, including its mandated negative fixture: a policy that asserts realized episode state must be rejected.behavior_specifications.*.episode_policy(profileparticipant-episode-policy/v1) declares at least one of these elements:initialization: precondition assertions for every new episode generation.interaction_structure: turns ordered by thedecision-epochauthority, and the action contracts a turn offers. Each must belong to the owning specification and to every participant it selects.terminal_conditions: keyed conditions. Acompletedcondition names invariant or postcondition assertions. Atimed_outcondition names one deadline, window, or duration constraint that binds the specification or every participant it selects.truncation_conditions: keyed conditions that name invariant or postcondition assertions and end the episode astruncated. They carry noterminal_reason, and none may reuse the exact assertion set of acompletedcondition.reset_policy: the admittedreset/restartcontrol actions and the ADR-095 participant-memory scope. As on the ADR-095 decision-surface assurance and information-state contracts,episode_local_resetnames amemory_reset_authority_refandpersistent_across_episodesnames none. The policy does not supply those contracts' values. The authority must resolve to exactly one declared targetable element, such asagents.analystornodes.siem.services.console; a dangling or ambiguous ref is rejected.Each condition maps to exactly one ADR-013 terminal reason and names the evidence requirements that back the transition. A condition holds only when every assertion it names holds. Validation checks that each named evidence requirement is declared, not which record it captures.
interruptedcannot be authored. A participant is governed by at most one episode policy, by name or by role, because realized episodes are keyed by participant. Checks that need a participant selection or a reference still written as a${var}wait for the post-instantiation pass. The record rejects realized episode coordinates (episode_id,status, timestamps, sequence numbers,decision_epoch, a terminal reason outside a condition) with a diagnostic that names the ADR-013 contracts. Compilation emits one record per policy in the newRuntimeModel.participant_episode_policiesmap. Each record is keyed to the selected participants'participant.behavior.<agent>addresses, the same keys that ADR-013 episode state uses, and carries the reset authority's canonicalsdl.*address. Nothing plans, executes, or evaluates the policy, and no executable or runtime adoption is claimed.Because this changes source bound by the research evidence, both captures are republished at the next free releases (specification coverage 69.0.0, formal validation 70.0.0); retained outcomes, classifications and claim limits are unchanged. Two formal compile controls record digest-only deviations, because the compiled runtime model gains the new field.
Requirement UIDs
DSL-120. Issue Participant Episode Structure And Termination Surface (DSL-120) #307 namesDSL-120as the CI branch UID. This branch name carries none, because aDSL-120branch fails requirement governance on ownership. With the UID forced,tools/check_requirement_governance.py --base-rev origin/dev --requirement-uid DSL-120reports 18 failures. Seven arerequirement-ownership-mismatch, because thesdl-languageownership roots intools/policy/requirement_order.yamldo not include these files:contracts/fixtures/sdl/participant-episode-policy-v1/README.md,contracts/fixtures/sdl/participant-episode-policy-v1/valid/analyst-shift-episode.yaml,contracts/fixtures/sdl/participant-episode-policy-v1/invalid/realized-episode-state.yaml,docs/public/participant-control.md,docs/requirements/DSL-120/requirement.md,specs/concept-authority/semantic-profiles.md, andspecs/formal/assurance-fulfillment.yaml(tracked in Requirement ownership roots do not cover the files of DSL-117, DSL-120, DSL-121, ACT-624, SEM-223 and SEM-204 #1510). The other 11 are trace lines thatdocs/requirements/DSL-120/requirement.mddoes not record: IMPLEMENTS forraes/_language_metadata.py,raes/_mapping_scopes.py,raes/validator/__init__.py,raes/validator/_content_objectives.py,raes_processor/compiler/addresses.py,raes_processor/compiler/pipeline.py,raes_processor/models/__init__.py, andraes_processor/models/runtime_model.py, and TESTS for the three evidence modules listed under Traceability as revision pins only. Without a UID, the policy runner skips requirement governance.Related Issues
Closes #307
ADR Impact
Changes
raes/participant_episode_policy.py(new): the closedParticipantEpisodePolicyrecord and its parts. Every part rejects realized episode fields by name (the field sets come fromParticipantEpisodeExecutionState,ParticipantEpisodeHistoryEvent, anddecision_epoch). Terminal conditions are a discriminated union onterminal_reason(completedortimed_out). Truncation conditions carry no reason field and no temporal reference, and a strayterminal_reasonthere gets its own diagnostic. Condition keys are portable identifiers, unique across both maps, and a truncation condition may not reuse the exact assertion set of a completion condition, so one evidenced fact never maps to bothcompletedandtruncated. Reference items are non-blank in the model and the schema. The reset policy pairsepisode_local_resetwithmemory_reset_authority_ref, asParticipantDecisionSurfaceAssuranceV2ModelandParticipantInformationStateRecordModeldo, and its schema states the same pairing withif/then/else.raes/participant_behavior_specification.py: optionalepisode_policymember, excluded from dumps when absent, so policy-free specifications keep their existing canonical shape.raes/validator/_participant_episode_policies.py(new), wired throughraes/validator/__init__.pyand one call in_content_objectives.py: assertions must resolve with the right role. Turn actions must belong to the owning specification and to each selected participant'sactions, like the tool-affordance and autonomous-execution checks. Timeouts must name a deadline/window/duration constraint that binds the specification or every selected participant (explicit or role-selected), like the autonomous window rule. Evidence requirements must resolve, and at most one policy may govern each participant, like the autonomous owner-conflict rule. The reset authority must resolve to exactly one declared targetable element through the shared named-reference check thatauthority_scope_refsuses, so a dangling or ambiguous authority is rejected. Checks that depend on a${var}participant selection, role, action list, or reference are skipped before instantiation and run again after it.raes/_mapping_scopes.py: condition maps are literal-key maps, so condition identifiers keep their spelling and${var}keys are rejected.raes/composition/_behavior.py: module composition rewrites the policy's assertion, action, temporal, evidence, and reset-authority references and keeps condition identifiers local.raes/_language_metadata.py: editor completions forepisode_policy,assertion_refs, andtemporal_constraint_ref.raes_processor/models/participant_episode_resources.py(new) andraes_processor/compiler/participant_episode_policies.py(new), registered inaddresses.py,pipeline.py,models/runtime_model.py, andmodels/__init__.py:ParticipantEpisodePolicyRuntimeatparticipant.episode-policy.<name>with resolved assertion, action, time, and evidence addresses and the reset authority's canonicalsdl.<section>.<name>address (memory_reset_authority_address). The compiler resolves that address through the pipeline's declaration index (pipeline.pypasses it in), raises if a validated ref does not resolve to one declaration, and lists the address inrefresh_dependencies. The compiler returns early when no specification declares a policy.ParticipantEpisodeConditionRuntime.__post_init__re-asserts on the compiled record that the reason iscompleted,timed_out, ortruncated, that evidence is present, and that onlytimed_outuses a temporal constraint.ParticipantEpisodePolicyRuntime.__post_init__re-asserts that a reset authority address is present exactly when the scope isepisode_local_reset.sdl-authoring-input-v1,instantiated-scenario-v1,instantiated-scenario-snapshot-v1,materialized-scenario-v1, andscenario-satisfiability-evidence-v1regenerated fromschema_bundle(), withlast_changeledger entries undercontracts/schema-publication/entries/. The manifest itself is the v2 pointer and is unchanged.materialized-scenario-v1.jsonis 511,867 bytes, inside the 512,000-byte budget thattest_issue_1241_schema_publication_size.pyenforces (the merge-order hazard on currentdevis tracked in The materialized-scenario-v1 schema exceeds its 512,000-byte budget if #1463 lands before #1467 #1556). Three parser rules stay out of the schema: a policy must declare at least one element (like the behavior-specification aggregate rule, and the budget leaves no room for theanyOf), condition keys must differ across the two maps, and a truncation condition must not reuse a completion condition's assertion set (JSON Schema cannot compare keys or values across two objects). The reset authority stays a string in the schema; its resolution is a semantic-validation rule.contracts/fixtures/sdl/participant-episode-policy-v1/:valid/analyst-shift-episode.yaml(ahuman-supervisedparticipant with every element) andinvalid/realized-episode-state.yaml(the mandated negative: the same policy assertingstatus,initialized_at,decision_epoch, andterminal_reason), plus a README.specs/sdl/references.md: nine reference rows, including thetargetablereset-authority row (fatal dangling or ambiguous), checked against the newtools/sdl_catalog_parity/_expectations_4.py(registered in_registry.py).specs/sdl/sections.md: new "Participant episode structure" normative section.docs/explain/sdl/sections.md: authoring guide with an example.docs/explain/sdl/lineage.md: DSL-120 lineage and delivery-evidence bullets. The lineage ledger is unchanged because no top-level field, concept family, or reference model is added.docs/public/participant-control.md: one Scenario-author bullet forepisode_policy, and a link to the valid fixture.specs/concept-authority/semantic-profiles.md: replaces the sentence that said SDL has no episode authoring syntax. The profile JSON is unchanged.specs/formal/assurance-fulfillment.yaml: records Participant Episode Structure And Termination Surface (DSL-120) #307's delivered unit tests and typed contract, and removes Participant Episode Structure And Termination Surface (DSL-120) #307 from the two waivers that tracked it.docs/requirements/DSL-120/requirement.md: 13 traceability lines.status(DRAFT) andupdated_atare unchanged.execution-snapshot-v69.json,analysis-v69.json, issue-307 bundle) replays the retained matrix against this branch's source.execution-snapshot-v70.json,analysis-v70.json,retest-v70.json) replays the retained formal cases with baseline 69.0.0.compile-repeatability-controlandcompile-non-vacuity-controlkeep their outcomes, and only theirresult_digestchanges, recorded as acceptedcompiled-policy-metadatadeviations (precedent: feat: carry authored execution and recovery requirements #1413's execution-policy field).tools/check_specification_coverage.py,tools/formal_semantic_validation/, and the three evidence test modules. Both research indexes record the new releases.Test Plan
uv run --project implementations/python --frozen --all-extras python -m pytest implementations/python/tests/test_issue_307_dsl_120_participant_episode_policy.py -q -p no:cacheproviderpassed (75 passed). The same command with-m integrationselected nothing (75 deselected), because the module has no integration-marked tests.The tests fail without the change. With
implementations/python/packageschecked out fromorigin/dev, the module fails at collection (ImportErrorfromraes_processor.models). With that import moved into the two tests that use it, all 75 cases fail.The review-round cases were written before the fix. Run against the previous head
cbf38eeesource, the updated module gave 11 failed, 64 passed. The failures were the dangling (analyst-console-reset) and ambiguous (ticket-closed, both an assertion and a proposition) reset-authority rows, the three reset-authority address cases, the namespaced authority in the module-composition case, the${var}reset-authority revalidation case, the truncation-alias case, and the three compiled-record pairing cases.The tests are not vacuous. At this head, six temporary mutations, applied one at a time and restored before the next run, each failed the cases they cover: ignoring the reset authority in the validator (3 failed), leaving it un-namespaced in composition (1), dropping it from
refresh_dependencies(3), rendering the raw section instead of thesdl.*address (5), skipping the compiled pairing check (3), and accepting a truncation alias of a completion (1). At the previous headcbf38eee, 22 earlier mutations, applied the same way, each failed their cases:_content_objectives.pyfailed 17 cases.${var}participant selection, or a${var}action list, as resolved failed the matching deferral case.terminal_reasondiagnostic failed its case.NESTED_HASHMAP_FIELDSfailed 56 cases, because hyphenated condition keys are then rejected as non-canonical fields.completedfailed the compilation case.nullfailed the policy-free-shape case.assertion_refscompletion failed one language-service case.interruptedIR case.sdl-authoring-input-v1.json, removing the reference-itempatternfailed the blank-ref schema case, and removing the reset-policyallOffailed both reset-authority schema cases.With the change, 22 related modules plus the new one passed: catalog parity, lineage, language service, DSL-142 delivery, ACT-617 mixed control, classification migration, instantiated-scenario schema, example schema conformance, three #1241 schema modules (materialization schemas, schema omissions, publication size), processor manifest, reference models, SEM-208, YAML mapping keys, SDL parser, runtime models, assurance policy, semantic profiles, concept authority and its governance module, and #1361 policy composition (938 passed, 1 skipped, 1 deselected). With
-m integrationthey passed too (1 passed:test_live_sdl_catalogs_match_authorities).tools/check_generated_schemas.py,tools/check_schema_publication.py --base-rev origin/dev,tools/check_sdl_catalog_parity.py,tools/check_sdl_lineage.py, andtools/check_assurance_policy.pypass, and the review fixes leave every published schema unchanged.tools/check_specification_coverage.pyandtools/check_formal_semantic_validation.pypass (integrity and replay). The three evidence modules pass with default markers (209 passed, 19 deselected) and with-m integration(19 passed).nox -s contracts -- --base-rev origin/devpassed (14 of 14 steps).nox -s verify-fast-feedback -- --base-rev origin/dev,nox -s lint,make policy, andnox -s docs-local(public source boundary, Vale, executable quickstart, Sphinx HTML, output inventory) passed. The policy runner skips requirement governance on its own, because this UID-free branch has no requirement-scope file.No coverage regression: at head
a6218096, the SonarCloud PR gate is OK (96.9% new-code coverage, 0 new violations, 0.0% duplication), andcanonical / coverage-reducepassed in CI run 38059289132.Ground Control Checks
Traceability
implementations/python/packages/raes/participant_episode_policy.py,implementations/python/packages/raes/participant_behavior_specification.py,implementations/python/packages/raes/validator/_participant_episode_policies.py,implementations/python/packages/raes/composition/_behavior.py,implementations/python/packages/raes_processor/compiler/participant_episode_policies.py,implementations/python/packages/raes_processor/models/participant_episode_resources.py,contracts/schemas/sdl/sdl-authoring-input-v1.json,contracts/schemas/sdl/instantiated-scenario-v1.json,specs/sdl/sections.md,specs/sdl/references.mdimplementations/python/tests/test_issue_307_dsl_120_participant_episode_policy.pyimplementations/python/tests/test_specification_coverage.py,implementations/python/tests/test_formal_semantic_validation.py,implementations/python/tests/test_issue_989_versioned_evidence.pyChecklist
ruff formatandruff checkclean; every touched package file stays under the 500-line cap;raes/_declarations.pyandraes_contracts/contracts/_exports.pyare untouched)episode_local_resetscope names its reset authority, which resolves to exactly one declared targetable element. A truncation condition never reuses a completion condition's assertion set. Each condition maps to exactly one ofcompleted,timed_out, ortruncated, and names evidence. The compiled records re-assert the reason and backing pairing and the reset-authority pairing. The FM3 abstract state machine is the Participant episode/reset & budget/quota: semantics + language surfaces + model (SEM-222, SEM-223, DSL-120, DSL-121, ACT-623, ACT-624) #122 design's and is unchanged. No executable or runtime adoption is claimed.featcuts a minor release for the new authoring surfaceDocumentation
Updated:
specs/sdl/sections.md,specs/sdl/references.md,docs/explain/sdl/sections.md,docs/explain/sdl/lineage.md,docs/public/participant-control.md,specs/concept-authority/semantic-profiles.md. Verified unchanged:docs/explain/sdl/limitations.md(pinned evidence artifact) and the ADR-013 text.