kernel: govern the M6 event pathway — t_hook firings stage governance_proposals (closes #53)#56
Merged
Merged
Conversation
…_proposals (closes #53) Parity with the TIME sweep per Sam ruling t250-Q4: event-fired t_hooks now stage an ADD-governance_proposal + firing_state pending->proposed pair instead of auto-applying react_template ungoverned (fp-fruits finding v, F-a class). Watcher/reactor (WF17 Pass-1) keeps immediate apply - same class, out of ruling scope, flagged follow-up. - reactive: Firing{Proposal,SourceHook,Kind} + EvaluateDetailed; Evaluate stays as a provenance-erasing wrapper (call sites unchanged) - kernel: stageHookProposalPair extracted from SweepOnce (shared builder, parity by construction); runReactive routes by Kind - stageEventHookLocked: firing_state idempotency filter (sweep parity), substituted proposed_envelope normalized to JSON map (CI-4 Go-value replay parity), per-firing URN discriminator -evt<seq>-n<i>, M8 gate pre-flight on the whole pair (fail-closed batch parity), PropertySpec injection + registry-less fallback - applyStagedLocked: staging apply that mirrors ApplyProgram's checks (no ValidateMUTATE - the sweep path never calls it; requiring a category would reject hooks carrying explicit firing_state and spam duplicates) - applyReactiveLocked returns bool (landed or not) - tests: THookFires rewritten as THookStagesProposal; new THookExplicitPendingStages, THookGateBlocksStaging, THookSameSlugNoCollision, THookEventIdempotency Adversarial review (12 agents, 3 lenses, refute-verify): 8 confirmed findings folded (4 root defects: ValidateMUTATE standard-path rejection -> duplicate-proposal spam; M8 gate bypass; same-slug URN collision; typed- struct vs replay-map divergence). Live throwaway gates: additive AND explicit-pending cases stage exactly (+3), template withheld, idempotent. Zero live react_templates fleet-wide (5 folds inventoried) -> no load-bearing fast path -> ruling default (govern), no allowlist machinery. authored-by: agent:claude-cowork.hp-z440 / session:sam.z440-cowork-workspace / t250-m6-event-governance Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR changes the kernel’s M6 event-pathway handling of t_hook firings so they no longer immediately apply react_template results, and instead stage them as governed governance_proposal + firing_state transitions to match TIME sweep behavior.
Changes:
- Adds provenance-aware reactive evaluation (
EvaluateDetailed) so the runtime can distinguisht_hookfirings from watcher/reactor firings. - Extracts and reuses a shared staging-pair builder (
stageHookProposalPair) for both TIME sweep and event-pathway staging. - Implements event-pathway staging in the runtime with idempotency filtering, M8 gate preflight on the whole pair, and replay-parity normalization of
proposed_envelope, plus new tests for these behaviors.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| internal/reactive/engine.go | Introduces Firing and EvaluateDetailed to carry provenance (reactor vs t_hook) to the kernel. |
| internal/kernel/sweep.go | Extracts stageHookProposalPair so sweep staging and event staging share the same two-envelope shape. |
| internal/kernel/runtime.go | Routes reactive firings: stage t_hook firings as proposals; keep watcher/reactor immediate apply; adds staging helper paths. |
| internal/kernel/runtime_reactive_test.go | Replaces the prior fast-path test with governed staging tests (idempotency, gates, collisions, explicit pending). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+594
to
+599
| switch f.Kind { | ||
| case "t_hook": | ||
| rt.stageEventHookLocked(f, trigger, i) | ||
| default: // "reactor" — WF17 watcher/reactor chain, unchanged. | ||
| rt.applyReactiveLocked(f.Proposal) | ||
| } |
Comment on lines
+27
to
+31
| type Firing struct { | ||
| Proposal graph.Envelope | ||
| SourceHook graph.URN // set when Kind == "t_hook" | ||
| Kind string // "reactor" | "t_hook" | ||
| } |
…il-closed routing on unknown kinds authored-by: agent:claude-cowork.hp-z440 / session:sam.z440-cowork-workspace / t250-m6-event-governance Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
HG URN: urn:moos:session:sam.kernel-proper
Summary
react_templateresults ungoverned: event-fired t_hooks now stage an ADD-governance_proposal+firing_statepending→proposed pair — parity with the TIME sweep (Sam ruling t250-Q4, recorded93c86ce; fp-fruits finding v).reactive.Firing+EvaluateDetailedadd pass provenance (reactor|t_hook);Evaluatestays a thin wrapper (all call sites unchanged).stageHookProposalPairextracted fromSweepOnce— parity by construction; sweep behavior byte-preserved (URN scheme, counter arithmetic, property set).proposed_envelopenormalized to JSON-map form (CI-4 Go-value replay parity), per-firing URN discriminator-evt<seq>-n<i>, M8 gate pre-flight on the whole pair (fail-closed batch parity), PropertySpec injection + registry-less fallback.applyStagedLockedmirrors ApplyProgram's checks for kernel-internal staging (no ValidateMUTATE — the sweep path never calls it; requiring a rewrite_category would silently reject hooks carrying explicit firing_state and spam one duplicate proposal per trigger).Why
runtime.gorunReactivefolded t_hook react_template results straight into state — skipping §M11/§M12, M8 gates, and the firing_state machine (F-a class). Ruling: govern it, unless a load-bearing fast path is demonstrated. Fleet inventory: zero live react_templates across all 5 reachable folds → the ruling's default branch; no allowlist machinery built (nothing to declare — a future consumer that needs the fast path is the change that declares it).Watcher/reactor (WF17 Pass-1) keeps immediate apply — same F-a class, out of this ruling's scope; follow-up issue to be filed.
Adversarial review (pre-PR)
12-agent, 3-lens refute-verify workflow: 8 confirmed findings → 4 root defects, all folded:
graph.Envelopelive vsmap[string]anyreplayed — CI-4 Go-value divergence (minor)Validation
Live throwaway :8899 (real 4.0.1 ontology, registry mode), both hook shapes:
-ndiscriminator:urn:moos:proposal:kernel.<slug>-t250-evt<seq>-n0New tests:
THookStagesProposal(rewrites the old fast-path test),THookExplicitPendingStages,THookGateBlocksStaging,THookSameSlugNoCollision,THookEventIdempotency.Notes
Closes #53
🤖 Generated with Claude Code