Skip to content

Enforce participant flow policy at final runtime sinks #1003

Closed

Description

@Brad-Edwards

Parent: #812

Bounded outcome

Extend RUN-319 so every governed external action or disclosure resolves SEM-233 effective labels, exact policy/state cut, authority, destination, and API-407 support immediately before RuntimeTarget dispatch or serialization. Commit the decision atomically before effect and preserve idempotent, append-only evidence.

Negative cases

  • Enforcement only at planning, schema validation, action admission, gateway, prompt, monitor, or request construction.
  • Backend dispatch or participant-visible output before the durable permit decision.
  • Missing label/provenance, stale cut, unsupported capability, policy denial, failed expected-head check, or failed commit causing any external effect.
  • Streaming chunks, errors, tool arguments, callbacks, or handoffs bypassing the sink policy.
  • Unsafe raw values in diagnostics, logs, audit, or error envelopes.

Evidence required

  • Boundary tests through the real RuntimeControlPlane and instrumented RuntimeTarget.
  • Zero target-call and zero disclosure assertions for every denial class.
  • Atomic store, history-head, idempotency, replay, restart, and both shipped-store evidence.
  • Authenticated identity/target/participant/controller/audience binding tests.
  • Safe bounded diagnostics and audit/evidence assertions.

Explicit nonclaims

  • Reference-runtime enforcement is not backend realization or universal information-flow control.
  • No undeclared timing/covert-channel, opaque apparatus, monitor-honesty, or model-alignment claim.

Dependencies

Requirements

  • SEM-233
  • RUN-319
  • RUN-310
  • API-423
  • API-407

Activity

  1. added
    enhancementNew feature or request
    securitySecurity vulnerabilities and hardening issues
    area:runtimeRuntime and control-plane code
    in-progressAn agent is actively working this issue via /implement
    on Jul 30, 2026
  2. Brad-Edwards commented on Aug 2, 2026

    @Brad-Edwards
    CollaboratorAuthor

    🛠️ Picked up by /implement - driver claude, branch 1003-runtime-sink-flow-enforcement, 2026-08-02T16:22:44.634Z.

  3. Brad-Edwards commented on Aug 2, 2026

    @Brad-Edwards
    CollaboratorAuthor

    gc workflow phase recorded: preflight (issue #1003). Posted by the MCP server to enforce ordering between workflow steps (issue #794 MVP-2). Do not edit or delete — used by downstream tools to gate phase prerequisites.

  4. Brad-Edwards commented on Aug 2, 2026

    @Brad-Edwards
    CollaboratorAuthor

    gc workflow phase recorded: preflight (issue #1003). Posted by the MCP server to enforce ordering between workflow steps (issue #794 MVP-2). Do not edit or delete — used by downstream tools to gate phase prerequisites.

  5. Brad-Edwards commented on Aug 2, 2026

    @Brad-Edwards
    CollaboratorAuthor

    gc workflow phase recorded: preflight (issue #1003). Posted by the MCP server to enforce ordering between workflow steps (issue #794 MVP-2). Do not edit or delete — used by downstream tools to gate phase prerequisites.

  6. Brad-Edwards commented on Aug 2, 2026

    @Brad-Edwards
    CollaboratorAuthor

    gc workflow phase recorded: preflight (issue #1003). Posted by the MCP server to enforce ordering between workflow steps (issue #794 MVP-2). Do not edit or delete — used by downstream tools to gate phase prerequisites.

  7. Brad-Edwards commented on Aug 2, 2026

    @Brad-Edwards
    CollaboratorAuthor

    gc workflow phase recorded: preflight (issue #1003). Posted by the MCP server to enforce ordering between workflow steps (issue #794 MVP-2). Do not edit or delete — used by downstream tools to gate phase prerequisites.

  8. Brad-Edwards commented on Aug 2, 2026

    @Brad-Edwards
    CollaboratorAuthor

    gc workflow phase recorded: plan (issue #1003). Posted by the MCP server to enforce ordering between workflow steps (issue #794 MVP-2). Do not edit or delete — used by downstream tools to gate phase prerequisites.

    Implementation plan — Enforce participant flow policy at final runtime sinks (#1003)

    Requirements in scope: SEM-233, RUN-319, RUN-310, API-423, API-407 (all ACTIVE). Base branch dev (blocker #1002/PR #1053 is merged into dev).

    Problem statement (the gap)

    #1002 (PR #1053) published the portable SEM-233 final-sink flow-control contracts in raes_contracts — ParticipantFlowControlRelationModel, ParticipantFlowSinkDecisionModel, ParticipantFlowControlValidationContext, and validate_participant_flow_control_resolved_context(). These are not consumed anywhere in raes_runtime. The reference runtime today resolves and commits only the older API-423 crossing decision (prepare_participant_crossing → commit_prepared_crossing), and does not resolve the SEM-233 effective-label / exact-cut / release-authority / destination / API-407-capability final disposition before a RuntimeTarget effect or serialization. The architecture preflight (docs/decisions/issue-1003-sem-233-final-runtime-sinks-preflight.md, created by Step 2.5, kept as the binding note) is the governing guidance.

    Per ADR-101 the final RAES-controlled boundary is after exact policy/authority/destination/capability/state-cut resolution and before a RuntimeTarget component performs an external action or any participant/external value is serialized, streamed, persisted, returned in an error, callback, or handoff.

    Design (fail-closed, one decision bound to the committed state cut)

    Wire the SEM-233 final-sink decision into the existing operation-bound crossing transaction — no new store, policy engine, audit channel, exception hierarchy, or generic sink/dispatcher. All work stays inside the _participant_control_lock prepare→commit window that both real sinks already use.

    1. New shared final-sink guard — implementations/python/packages/raes_runtime/participant_flow_sink.py.

      • A single narrow helper (resolve_participant_flow_sink_decision(control_plane, prepared, *, sink_kind, ...)) that every real target invocation / disclosure writer must call. It delegates to validate_participant_flow_control_resolved_context(); it does not re-implement any join.
      • It obtains the trusted SEM-233 relation + ParticipantFlowControlValidationContext from a server-side resolver method on the existing _crossing_policy_resolver (new optional protocol method resolve_flow_sink_decision(...) — no wire input, no caller-supplied relation/labels/profile/authority/sink/disposition). The context carries the already-validated API-423 occurrence, exact profile/policy/cut, source labels + provenance, ParticipantFlowSinkCoordinate (destination/audience), release authority, ParticipantFlowActionAdmissionResolution, ParticipantFlowCapabilityResolution (API-407 via resolve_participant_feature_support()), and ParticipantFlowHistoryHeadResolution bound to the same expected history heads as the prepared crossing.
      • Permit iff SEM-233 final_disposition == PERMIT and the referenced API-423 decision, SEM-211 admission (where applicable), SEM-226 projection (where applicable), API-407 capability result, authenticated principal/target/participant/controller/audience bindings, and current history heads all agree. Missing / stale / ambiguous / unresolved / unsupported / denied / mismatched → a preserved non-permit reason class (DENY/UNSUPPORTED/STALE/UNRESOLVED), never collapsed into an implicit permit or an unbounded error.
      • Evidence is reference, not raw payload: the guard folds the SEM-233 sink-decision reference (document_id + digest + decision_id) into the PreparedParticipantCrossing record/history so it is written in the same commit_participant_transition set as the API-423 decision. The relation document itself is a resolver-side trusted artifact (like flow-policy profiles loaded via load_participant_boundary_flow_policy_profile_revision), not stored raw in the snapshot. If a closed reference field must be added to a published crossing/flow schema under contracts/schemas/, record the last_change change-ledger entry in contracts/schema-publication-manifest.json and keep schema_bundle() byte-identical (tools/check_generated_schemas.py). Preferred path: reuse existing evidence_refs/required_evidence_refs plumbing to carry the reference and avoid a schema change.
    2. Instrument every real sink — the guard is invoked inside the existing transaction window, before the effect:

      • Egress serialization: participant_crossing_egress.py::serialize_participant_view — resolve+bind the SEM-233 permit before the governed view is committed/returned; non-permit → commit denial, PermissionError, zero disclosure.
      • Ingress action admission: participant_crossing_boundary.py::execute_action_ingress_crossing — resolve+bind before the apply_authorized_participant_action backend call (line 229); the authorization commit already precedes the effect, the SEM-233 permit joins that same commit. record_participant_control (RUN-310 control ingress) gets the same guard so intervention/handoff/approval crossings resolve a final-sink permit.
      • Ensure no bypass: audit the other RuntimeControlPlane target-dispatch paths (participant_control.py lifecycle initialize/reset/restart/terminate, control_plane_execution.py) for governed external effects/disclosures; any that reach a RuntimeTarget component with participant-relative scope route through the same guard. Legacy non-participant provisioning/orchestration/evaluation plan submission is out of scope and remains unchanged (it is not a participant-governed disclosure).
    3. Commit-before-effect + later facts separate. commit_participant_transition() remains the sole durable pre-effect transaction across both shipped stores (InMemoryControlPlaneStore, LocalControlPlaneStore) with expected-head guarding. After a successful commit, invoke only the authorized target / serialize only the governed projection. Backend failure, delivery, observation, callback completion, and audit retention stay later append-only facts with predecessor refs (existing _with_opacity_egress_observation pattern), never pre-committed as delivery.

    4. Idempotency + replay. The operation fingerprint and expected heads bind the same semantic cut the flow decision used; a profile/policy/label/provenance/release/sink/audience/capability/controller/target/head change conflicts and must not reuse a prior permit (extend _semantic_fingerprint / _require_replay_state_cut).

    5. Restart validation. Extend validate_persisted_crossing_history (or add a sibling invoked from the RuntimeControlPlane constructor for both stores) to revalidate any persisted SEM-233 final-sink reference against the resolver's trusted context on load; unresolved → fail closed (no serving/mutating).

    Cross-cutting design review (FAANG-L6 / preflight §Security layers)

    • Security: trusted server-side resolver only (no caller-selected file/URL/profile/relation/disposition); separate participant / controller / audience bindings via ControlPlaneIdentity (role or API-408 admin read is not disclosure authority); bounded value-independent denial reasons; unexpected failures stay {"detail":"internal server error"}; no raw values, prompts, policy bodies, tokens, backend exceptions, URLs, env, or argv in diagnostics/audit/logs/evidence; a digest is not automatically safe-to-disclose content. No subprocess/secret-loader/env-binding/plugin added.
    • Maintainability: reuse the incumbents in the preflight table (prepare_participant_crossing, commit_participant_transition, PreparedParticipantCrossing, expected_participant_history_heads, resolve_participant_feature_support, ControlPlaneOperationRecord, AuditEvent, Diagnostic); the guard composes owning validators, never copies joins into routes/adapters/tests.
    • Extensibility: the seam is the closed SEM-233 sink coordinate (sink_kind, sink_ref, destination_ref, audience_scope_ref) + trusted non-wire context + expected-head write set. A future stream/callback/persistent-write/multi-part sink adds a closed sink variant that calls the same pre-effect decision/commit boundary; streaming requires a decision before the first byte and retains the bound decision/cut per chunk; error paths and handoffs are sinks too.
    • Whole-repo view: touches only raes_runtime + tests (+ optional contracts/schemas ledger if a reference field is published + optional docs/migration/participant-information-flow-control.md note). Respects .gc/plan-rules.md: no authority artifacts outside specs//contracts//docs//implementations/; no CHANGELOG.md/changelog.d//_version.py edits; keep IMPLEMENTS/TESTS traceability aligned; RAES_REQUIREMENT_UID=RUN-319 for verify (branch carries no UID).

    Tests (TDD, boundary-driven — implementations/python/tests/test_issue_1003_final_sink_flow_enforcement.py)

    Drive the real RuntimeControlPlane with an instrumented RuntimeTarget that counts backend/target calls, plus a trusted test flow-control resolver (built on participant_crossing_fixtures.py, sem233_boundary_flow_model.py). Assert:

    • Zero target calls and zero disclosures for every non-permit class: missing label/provenance, stale cut, unsupported API-407 capability, policy denial, failed expected-head check, failed commit, resolver exception, replay-semantic mismatch, restart-validation failure.
    • Positive: successful permitted egress projection and ingress admission; SEM-233 evidence reference committed atomically with the API-423 decision; correct final disposition combination.
    • Idempotent replay returns the stored receipt only on exact semantic match; both shipped stores (InMemory, Local) preserve expected-head behavior and restart validation.
    • Authenticated identity / target / participant / controller / audience binding required before existence or content disclosure; transformed ingress re-admission and projected egress; streaming/callback/error/handoff paths do not bypass the guard.
    • Safe bounded diagnostics / audit / error envelopes (no raw values).
    • Regression: existing test_run_319_participant_flow_policy.py, test_sem_233_flow_control_contracts.py, test_api_423_participant_crossing_contracts.py, test_run_310_supervisory_lifecycle.py, test_runtime_control_plane*.py stay green.

    Traceability (reconciled post-merge at Steps 15–16)

    New participant_flow_sink.py → IMPLEMENTS SEM-233 + RUN-319; edits binding the final-sink permit → IMPLEMENTS RUN-319 (primary), with API-423 (evidence reference), API-407 (capability gate), RUN-310 (control-ingress lifecycle ordering) as the joins they enforce. New test file → TESTS SEM-233/RUN-319/API-423/API-407/RUN-310. All five requirements already ACTIVE — no DRAFT→ACTIVE transition needed; Step 15/16 reconcile links only.

    Gates before completion (per .gc/plan-rules.md)

    tools/check_repo_policy.py, tools/check_requirement_governance.py, tools/verify_all.py (via the verify nox session) all run at the completion boundary with RAES_REQUIREMENT_UID=RUN-319. PR title will be a valid Conventional Commit feat: (consumer-visible runtime enforcement) passing title-guard.

    Non-goals (preflight)

    Reference-runtime enforcement only — no universal information-flow control, backend realization, noninterference, covert/timing-channel control, monitor honesty, model alignment, or adversarial-robustness claim. No new policy language, transport, schema family, HTTP auth mechanism, or generic sink framework. Absence of crossing evidence never implies a permit or historical enforcement.

  9. Brad-Edwards commented on Aug 2, 2026

    @Brad-Edwards
    CollaboratorAuthor

    gc_codex_review — cycle 1 of 1 (pre-push) on issue #1003 (branch 1003-runtime-sink-flow-enforcement)
    Diff mode: inline — the complete diff was supplied in one prompt

    Core review

    Verdict: ship-with-fixes

    The change establishes a narrow SEM-233 enforcement seam at the existing RUN-319 crossing boundary and generally reuses the existing transaction, audit, and crossing machinery rather than inventing parallel infrastructure. That is the right shape, but the resolver result is treated as trusted beyond the validator: the runtime passes the actual sink kind into the resolver without binding the returned decision back to that sink coordinate, and its failure boundary is narrower than the declared fail-closed contract.

    Blocking findings (2):

    1. [one-off] Bind the resolved decision to the actual sink kind — implementations/python/packages/raes_runtime/participant_flow_sink.py:159
      The runtime passes sink_kind to the resolver but never verifies that decision.sink.sink_kind matches it after validating the returned relation. A resolver can therefore return an otherwise valid permit for (for example) PARTICIPANT_OUTPUT while this call is about to admit an ACTION_ARGUMENT; validation proves the relation is internally valid, not that it authorizes this concrete effect. Reject a decision unless its full applicable sink coordinate, at minimum its kind, is bound to the actual sink being invoked before committing or exposing the effect.
    2. [one-off] Fail closed for every resolver failure — implementations/python/packages/raes_runtime/participant_flow_sink.py:131
      The method promises that a resolver exception never leaks and never widens permission, but catches only four exception types. A resolver failure such as RuntimeError or an implementation-specific operational exception escapes this boundary instead of becoming the bounded non-permit decision required for a final-sink guard. Catch resolver failures at this boundary and convert them to the existing unresolved denial; preserve cancellation and process-control exceptions if the runtime has explicit handling for them.

    Security review

    Verdict: don't-ship

    This change places the intended guard at the right operational seams—control ingress, action ingress, and egress serialization—and reuses the existing crossing transaction/audit flow. However, the central resolver treats SEM-233 as optional and fails to bind the validated permit to the actual sink being effected. That leaves the final-sink boundary dependent on resolver convention rather than enforced runtime invariants, foreclosing safe addition of further sink kinds.

    Blocking findings (2):

    1. [class] Permit is not bound to the actual sink kind being invoked — implementations/python/packages/raes_runtime/participant_flow_sink.py:153
      The resolver result is validated as internally consistent, but the subsequent live binding checks participant, episode, history heads, and audience only. It never requires decision.sink.sink_kind == sink_kind (nor otherwise proves the resolved decision is for this effect). An attacker able to invoke a participant-output path can receive a value if the configured resolver returns a valid permit for another sink with the same participant/audience/state cut, such as an action-argument sink. Passing sink_kind into a resolver is not an enforcement boundary: a stale, overly broad, or incorrectly implemented resolver can ignore it while returning a fully validator-valid relation. Require exact equality between the resolved decision's sink coordinate and the concrete sink being executed before permitting the effect.
    2. [class] Resolvers without the new hook bypass final-sink enforcement — implementations/python/packages/raes_runtime/participant_flow_sink.py:113
      A resolver that does not implement resolve_flow_sink_decision causes this helper to return None, which every caller interprets as authorization to perform the effect. This makes final-sink enforcement silently absent for existing resolver deployments rather than fail closed. An attacker who can submit an otherwise API-423-authorized action/control request, or request an authorized projection, can reach the backend or receive serialized output without any SEM-233 final-sink decision whenever that deployment uses a legacy resolver. Missing enforcement capability must deny the final sink (or be rejected during resolver/control-plane configuration), rather than preserving the legacy permit path.
  10. Brad-Edwards commented on Aug 2, 2026

    @Brad-Edwards
    CollaboratorAuthor

    gc_codex_review pre-push cycle 1 of 1 complete for issue #1003 on branch '1003-runtime-sink-flow-enforcement'. Posted by the MCP server to enforce the pre-push hard-cap-1 contract (issues #796, #804, #906). Do not edit or delete — used by the next gc_codex_review (uncommitted) invocation to count cycles.

  11. Brad-Edwards commented on Aug 2, 2026

    @Brad-Edwards
    CollaboratorAuthor

    Review decision record — codex cycle 1 (issue #1003)

    Reviewer: codex
    Cycle: 1

    Architectural read:

    Core reviewer: The change establishes a narrow SEM-233 enforcement seam at the existing RUN-319 crossing boundary and generally reuses the existing transaction, audit, and crossing machinery rather than inventing parallel infrastructure. That is the right shape, but the resolver result is treated as trusted beyond the validator: the runtime passes the actual sink kind into the resolver without binding the returned decision back to that sink coordinate, and its failure boundary is narrower than the declared fail-closed contract.

    Security reviewer: This change places the intended guard at the right operational seams—control ingress, action ingress, and egress serialization—and reuses the existing crossing transaction/audit flow. However, the central resolver treats SEM-233 as optional and fails to bind the validated permit to the actual sink being effected. That leaves the final-sink boundary dependent on resolver convention rather than enforced runtime invariants, foreclosing safe addition of further sink kinds.

    Blocking findings: 4

    Finding 1 — one-off

    • ID: F1
    • Title: [core] Bind the resolved decision to the actual sink kind
    • Location: implementations/python/packages/raes_runtime/participant_flow_sink.py:159
    • Decision: fix
    • Rationale: The runtime passes sink_kind to the resolver but never verifies that decision.sink.sink_kind matches it after validating the returned relation. A resolver can therefore return an otherwise valid permit for (for example) `PARTICIPANT_OU…

    Finding 2 — one-off

    • ID: F2
    • Title: [core] Fail closed for every resolver failure
    • Location: implementations/python/packages/raes_runtime/participant_flow_sink.py:131
    • Decision: fix
    • Rationale: The method promises that a resolver exception never leaks and never widens permission, but catches only four exception types. A resolver failure such as RuntimeError or an implementation-specific operational exception escapes this bounda…

    Finding 3 — class (4 instances)

    • ID: F3
    • Title: [security] Permit is not bound to the actual sink kind being invoked
    • Location: implementations/python/packages/raes_runtime/participant_flow_sink.py:153
    • Decision: fix
    • Rationale: The resolver result is validated as internally consistent, but the subsequent live binding checks participant, episode, history heads, and audience only. It never requires decision.sink.sink_kind == sink_kind (nor otherwise proves the re…
    • Instances:
      • implementations/python/packages/raes_runtime/participant_flow_sink.py:153
      • implementations/python/packages/raes_runtime/participant_crossing_boundary.py:134
      • implementations/python/packages/raes_runtime/participant_crossing_boundary.py:228
      • implementations/python/packages/raes_runtime/participant_crossing_egress.py:127

    Finding 4 — class (4 instances)

    • ID: F4
    • Title: [security] Resolvers without the new hook bypass final-sink enforcement
    • Location: implementations/python/packages/raes_runtime/participant_flow_sink.py:113
    • Decision: fix
    • Rationale: A resolver that does not implement resolve_flow_sink_decision causes this helper to return None, which every caller interprets as authorization to perform the effect. This makes final-sink enforcement silently absent for existing resol…
    • Instances:
      • implementations/python/packages/raes_runtime/participant_flow_sink.py:113
      • implementations/python/packages/raes_runtime/participant_crossing_boundary.py:134
      • implementations/python/packages/raes_runtime/participant_crossing_boundary.py:228
      • implementations/python/packages/raes_runtime/participant_crossing_egress.py:127
  12. Brad-Edwards commented on Aug 2, 2026

    @Brad-Edwards
    CollaboratorAuthor

    gc_test_quality_review cycle 1 of 1 — issue #1003

    Reviewer: test-quality (claude-sonnet-5 via gc_test_quality_review)
    Branch: 1003-runtime-sink-flow-enforcement
    Cycle: 1 / 1
    Findings: 1

    Finding 1 — [critical] implementations/python/tests/test_issue_1003_final_sink_flow_enforcement.py:41

    Problem: _NON_PERMIT_TOGGLES exercises every FlowSinkToggles field except return_non_resolution. That field exists specifically to drive Sem233FlowSinkResolver.resolve_flow_sink_decision to return None (a callable hook that doesn't raise, just returns the wrong type) — the exact case resolve_participant_flow_sink_decision's if not isinstance(resolution, ParticipantFlowSinkResolution): return _denied(...) guard (participant_flow_sink.py:140-141) exists to fail closed on. No test in this diff, and no test anywhere in the repo, calls the resolver with that toggle set or otherwise exercises that isinstance check.
    Why it matters: If that isinstance guard were deleted or weakened (e.g. changed to only check is None, or removed so a malformed resolver return value falls through to resolution.relation attribute access), no current test would fail — every existing toggle produces a real ParticipantFlowSinkResolution instance, valid or not. A regression here would either crash with an unhandled AttributeError (denial-of-service on the crossing boundary) or, worse, silently misbehave in a way that isn't fail-closed, and the security-outcome test (denied, zero backend dispatch, zero serialization) that would have caught it simply isn't run for this input class.
    Fix: Add a pytest.param(FlowSinkToggles(return_non_resolution=True), id="resolver-returns-non-resolution") entry to _NON_PERMIT_TOGGLES in test_issue_1003_final_sink_flow_enforcement.py so it flows through test_non_permit_ingress_never_dispatches_backend, test_non_permit_egress_raises_and_serializes_nothing, and test_non_permit_control_ingress_applies_no_transition the same as every other non-permit class.

  13. Brad-Edwards commented on Aug 2, 2026

    @Brad-Edwards
    CollaboratorAuthor

    gc_test_quality_review cycle 1 of 1 complete for issue #1003 on branch '1003-runtime-sink-flow-enforcement'. Posted by the MCP server to enforce the gc_test_quality_review hard-cap-1 contract (issue #884 follow-up, default lowered in #906). Do not edit or delete — used by the next gc_test_quality_review invocation to count cycles.

  14. Brad-Edwards commented on Aug 2, 2026

    @Brad-Edwards
    CollaboratorAuthor

    Review decision record — test-quality cycle 1 (issue #1003)

    Reviewer: test-quality
    Cycle: 1

    Architectural read:

    This is a well-shaped addition: a single new module (participant_flow_sink.py) owns the SEM-233 final-sink permit resolution, is wired into the three existing crossing boundaries (ingress action, control, egress) via a consistent resolve → deny/apply-audit pattern, and reuses the RUN-319 state-cut and API-423 validator rather than re-implementing any of it. The test suite matches that shape: it drives the real RuntimeControlPlane end-to-end, counts real backend dispatch, inspects committed audit/history state, and parametrizes across every non-permit disposition and binding-mismatch class the guard defines, including secret-leak checks on denial paths. That is the correct altitude for a security-boundary test — no mock-only assertions, no existence-only checks. The one gap is a fail-closed defensive branch (resolver returns a non-ParticipantFlowSinkResolution value without raising) that has a toggle built for it in the shared fixture module but is never wired into the parametrized non-permit cases, leaving that particular fail-closed guard with zero regression coverage.

    Blocking findings: 1

    Finding 1 — one-off

    • ID: F1
    • Title: (no title)
    • Decision: fix
    • Rationale: Addressed by next cycle
  15. added a commit that references this issue on Aug 2, 2026
    9670916
  16. Brad-Edwards commented on Aug 2, 2026

    @Brad-Edwards
    CollaboratorAuthor

    Ready for review — issue #1003

    PR: #1058

    Outcome

    Every governed participant action or disclosure now resolves a fresh exact-cut SEM-233 final-sink permit immediately before the runtime dispatches to a backend or serializes a participant-visible value. The permit is validated, bound to the concrete sink kind and the live crossing decision, participant, audience, and history-head cut, and committed atomically before any effect. Any denied, missing, stale, unsupported, or mis-bound input or resolver failure yields zero dispatch and zero disclosure. Enforcement is fail-closed by default at the last controllable runtime point.

    Files changed

    • (none)

    Reviews

    • codex: 3 findings fixed: bind permit to caller sink kind, fail closed on all resolver exceptions, and fail-closed-by-default enforcement (config-time rejection of a resolver without the hook).
    • test-quality: 1 finding fixed: added the return_non_resolution parametrized case exercising the isinstance fail-closed guard.

    Traceability reconciliation

    • Pending — requirement status transition and IMPLEMENTS/TESTS reconciliation run in Phase E once the PR merges.

    Status

    • CI: ✅ green
    • SonarCloud: ✅ passed
    • PR ready for user review and merge. Ground Control reconciliation (requirement status + traceability) runs on merge (Phase E).
  17. added a commit that references this issue on Aug 2, 2026
    6b47385
  18. Brad-Edwards commented on Aug 2, 2026

    @Brad-Edwards
    CollaboratorAuthor

    gc workflow phase recorded: traceability_reconciled (issue #1003). Posted by the MCP server to enforce ordering between workflow steps (issue #794 MVP-2). Do not edit or delete — used by downstream tools to gate phase prerequisites.

    • SEM-233: status=ACTIVE, IMPLEMENTS=6, TESTS=2
    • RUN-319: status=ACTIVE, IMPLEMENTS=21, TESTS=7
    • RUN-310: status=ACTIVE, IMPLEMENTS=6, TESTS=2
    • API-423: status=ACTIVE, IMPLEMENTS=11, TESTS=5
    • API-407: status=ACTIVE, IMPLEMENTS=17, TESTS=8
  19. Brad-Edwards commented on Aug 2, 2026

    @Brad-Edwards
    CollaboratorAuthor

    Final report — issue #1003 complete

    PR: #1058

    Outcome

    Every governed participant action or disclosure now resolves a fresh exact-cut SEM-233 final-sink permit immediately before the runtime dispatches to a backend or serializes a participant-visible value. The permit is validated, bound to the concrete sink kind and the live crossing decision, participant, audience, and history-head cut, and committed atomically before any effect. Any denied, missing, stale, unsupported, or mis-bound input or resolver failure yields zero dispatch and zero disclosure. Enforcement is fail-closed by default at the last controllable runtime point.

    In-scope requirements

    • SEM-233 (Participant boundary information-flow semantics) — ACTIVE
    • RUN-319 (Participant information-flow policy enforcement) — ACTIVE
    • RUN-310 (Supervisory lifecycle transitions) — ACTIVE
    • API-423 (Participant crossing policy and evidence contracts) — ACTIVE
    • API-407 (Backend participant feature-support declaration) — ACTIVE

    Files changed

    • (none)

    Reviews

    • codex: 3 findings fixed: bind permit to caller sink kind, fail closed on all resolver exceptions, and fail-closed-by-default enforcement (config-time rejection of a resolver without the hook).
    • test-quality: 1 finding fixed: added the return_non_resolution parametrized case exercising the isinstance fail-closed guard.

    Traceability reconciliation

    • IMPLEMENTS / TESTS / DOCUMENTS added: 0
    • Links updated: 0
    • Stale links removed: 0

    Status

    • CI: ✅ green
    • SonarCloud: ✅ passed
    • PR ready for user review and merge.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:runtimeRuntime and control-plane codeenhancementNew feature or requestin-progressAn agent is actively working this issue via /implementsecuritySecurity vulnerabilities and hardening issues

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions