You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Actor / identity binding for audit evidence (#14). New BuiltByBerry\LaravelSwarm\Audit\Actor value object (immutable id/type/name/metadata with Actor::system(), Actor::user($authenticatable), and Actor::fromAny() named constructors). New ActorResolver contract bound by default to DefaultActorResolver, which reads Context::get('swarm:actor') first (survives queue serialization), then falls back to auth()->user(), then null. Resolution happens once at every dispatch entry point (run, queue, broadcastOnQueue, dispatchDurable, stream) so attribution captures dispatch-time identity rather than worker-time. The resolved actor is stored under the reserved metadata.actor key, which EvidenceEnvelope now emits on every audit record regardless of the configured allowlist. New RunContext::withActor(Actor|Authenticatable|string|null) fluent setter overrides the bound resolver. New swarm.audit.actor.required config flag (env SWARM_AUDIT_ACTOR_REQUIRED, default false) — when true, runs without a resolvable actor throw MissingActorException at entry. Regulated callers (21 CFR Part 11, SOC 2) enable the flag and bind actor via Context::add('swarm:actor', $actor) before dispatch.
CapturePolicy contract for declarative capture decisions (#15). New BuiltByBerry\LaravelSwarm\Contracts\CapturePolicy (multi-method: inputs, outputs, artifacts, activeContext — each taking ?RunContext and ?Actor). New CaptureDecision enum (Full | Redact | Skip). New BooleanCapturePolicy bound by default; reads the existing swarm.capture.* booleans and returns Full when true, Redact when false — preserves v0.3 capture behavior exactly. Custom policies bind via $this->app->bind(CapturePolicy::class, MyPolicy::class) and make per-run decisions with context and actor visibility. SwarmCapture is refactored to delegate every capture decision to the bound policy; the public v0.3 surface (input(), output(), context(), step(), capturesInputs(), etc.) is unchanged so all 17+ existing injection sites continue to work.
SinkFailureHandler contract with halt support (#16). New BuiltByBerry\LaravelSwarm\Contracts\SinkFailureHandler returns a SinkFailureDecision enum (Swallow | RetryInline | Halt). New ConfiguredSinkFailureHandler bound by default maps the existing swarm.audit.failure_policy config values plus a new 'halt' value (alongside existing 'swallow' and 'log'). When the handler returns Halt, the dispatcher throws AuditSinkHaltedException, which carries the new HaltsSwarmExecution marker interface — SwarmRunner detects the marker and surfaces the halt as a deliberate run-level failure rather than swallowing it as an audit concern. The dispatcher retry loop is capped at SwarmAuditDispatcher::MAX_HANDLER_ITERATIONS = 5 to prevent runaway loops from buggy custom handlers; exceeding the cap throws a SwarmException with the original sink failure as $previous. Queue and DeadLetter decision cases are reserved for v0.5 alongside the audit outbox.
SwarmAuditSigner contract for tamper-evident evidence (#13). New BuiltByBerry\LaravelSwarm\Contracts\SwarmAuditSigner is invoked in the dispatcher after envelope enrichment and before sink emit. No default binding — when no signer is bound, the dispatcher emits payloads unchanged (v0.3 behavior preserved). Custom signers attach cryptographic signatures (HMAC, ECDSA, chain-signed hashes) to every audit record; implementations must not mutate or remove existing keys, only add signature fields. Signing failures route through the same SinkFailureHandler as sink failures, so callers who want strict halt-on-signing-failure set swarm.audit.failure_policy=halt. Signing scope (entire payload vs canonical subset), algorithm, and chain-signing semantics are implementation concerns.
Audit evidence envelope schema freeze.docs/audit-evidence-contract.md now formally commits to the v0.x envelope shape: schema_version, category, occurred_at, plus the enumerated category-specific correlation fields. Additive changes (new fields, new categories) ship within the v0.x line; breaking shape changes increment schema_version and land in a future minor with a per-version UPGRADING block. Sinks that parse strictly should switch on schema_version.
@internal PHPDoc applied across the codebase. 93 internal classes marked: runners, persistence stores, jobs, dispatchers, telemetry helpers, support utilities, Pulse Livewire components, and routing internals. Public surface (Facades, contracts, value objects, response DTOs, events, exceptions, Artisan commands, Pulse Recorders, SwarmServiceProvider, RunContext) deliberately left unmarked and committed to per the new ## Stability and the public API section in UPGRADING.md. Consumers can now grep @internal to distinguish package internals from the stability surface.
Changed
SwarmAuditDispatcher constructor signature changed: now takes (SwarmAuditSink, ConfigRepository, SinkFailureHandler, ?SwarmAuditSigner) — LoggerInterface is no longer injected directly (it moves into ConfiguredSinkFailureHandler). The dispatcher is marked @internal; application code that resolves it via the container is unaffected.
SwarmCapture constructor signature changed: now takes (ConfigRepository, CapturePolicy). The class is marked @internal; container-resolved usage is unaffected.
SwarmRunner constructor adds an ActorResolver dependency. The runner is marked @internal; container-resolved usage is unaffected.
composer.jsonextra.branch-alias.dev-main bumped from 0.3.x-dev to 0.4.x-dev.
Deprecated
The four swarm.capture.* boolean config keys (capture.inputs, capture.outputs, capture.artifacts, capture.active_context) are deprecated in favor of binding a custom CapturePolicy. The booleans remain functional through BooleanCapturePolicy and are scheduled for removal in v0.5 with a per-version UPGRADING block.