Bounded Autonomy Campaign Packet
Bounded autonomy campaign packets propose guarded agent work without authorizing source-file changes or unsupervised repair.
The write-up
Coverage gaps become proposals without action authority
This component lets an agent draft a plan to close its own coverage gaps while stamping every row as a proposal that carries no authority to act. bounded_autonomy_campaign_packet is a component that lets an agent draft a plan to close its own coverage gaps without giving that plan any authority to act. It reads synthetic public inputs, watches a read-only campaign builder, and emits a draft candidate packet where every row is stamped as a proposal, not a change.
The packet carries hashes and refs, never writes
The result record carries only refs, digests, line counts, and stdout and stderr hashes, never a write surface, a true source-file changes flag, or the builder's output bodies. The result record it writes carries refs, digests, line counts, and stdout and stderr hashes. It never carries a write surface, a source-file changes flag set to true, or the builder's output bodies.
The demonstration separates proposing from doing
What it demonstrates is narrow: an agent can propose work drawn from a real surface capable of doing it, observed in a mode where it did not. What it demonstrates is narrow and deliberate: an agent can propose work drawn from a real surface that could do that work, observed in a mode where it did not.
Purpose
The risk of sketching sliding into doing
An agent can usefully sketch a plan to fix its under-coverage, but the risk is that sketching quietly becomes doing as a proposal grows a write surface. An agent can usefully notice where it is under-covered and sketch a plan to fix it. The risk is that "sketch a plan" quietly becomes "do the work". A proposal grows a write surface, and a system meant to suggest starts editing its own source unsupervised.
Keeping proposing and acting apart
This component keeps proposing and acting apart, answering whether an agent can emit a draft campaign proposal from real coverage gaps without that proposal carrying any authority to act. This component keeps those two steps apart. It answers one question: can an agent emit a draft campaign proposal from real coverage gaps without that proposal carrying any authority to act on them?
Candidate count comes from a witnessed builder
The candidate count comes not from an invented list but from a check-only builder witness, and each candidate is stamped with no write surface, no source-file changes, and required review. The design choice that matters is where the candidate count comes from. The component does not invent a plausible list of work. It watches a real campaign builder run in a check-only mode and accepts its witness only when the builder reports candidate targets and leaves wrote_packet unset. Each drafted candidate is then stamped write_surface: none, source_mutation_authorized: false, and requires_human_review: true, so proposing can never be read as authorising.
How it works
Two entry points share the same checks
run and run_bounded_autonomy_bundle both route through run_crown_jewel_organ with the same evaluate and evaluate_negative_case evaluators, so the identical checks guard both command surfaces. run and run_bounded_autonomy_bundle both hand the fixture and the exported bundle to run_crown_jewel_organ, passing evaluate as the evaluator and evaluate_negative_case as the negative-case evaluator. The bundle entry point adds the bundle input mode. The same checks guard both command surfaces.
evaluate runs four ordered refusal checks
evaluate loads three inputs and runs four ordered checks, refusing a source-write policy, a failed witness, an empty list, or an authorising candidate, and passing only when no finding remains. evaluate loads three declared inputs: coverage_gaps.json, campaign_policy.json, and failed_campaign_digests.json. It then runs four checks in order and collects a finding for each failure. First, if write_source appears in the policy's allowed_actions, it records BOUNDED_AUTONOMY_SOURCE_WRITE_FORBIDDEN before any candidate is drafted. Second, it builds the candidate packet and refuses it if the builder witness did not pass or the packet is not marked drafted. Third, it refuses an empty candidate list. Fourth, it refuses any candidate that sets source_mutation_authorized to true or writes to the source surface. It also counts repeated entries in the failed digest ledger and records BOUNDED_AUTONOMY_REPEATED_FAILED_DIGEST if any digest appears more than once. A run passes only when the finding list is empty.
Turning the witnessed count into stamped rows
_candidate_packet_subprocess caps the witnessed count at the policy's max_candidate_count and turns it into draft rows, each tied to a coverage gap and stamped with no write surface and required human review. _candidate_packet_subprocess turns the witnessed target count into draft rows. It reads max_candidate_count from the policy (default 2), asks the witness for that many targets, and takes the smaller of the two counts. Each row ties to one coverage gap when one is available, carries the builder ref and the builder source digest, and sets write_surface: none, requires_human_review: true, and source_mutation_authorized: false.
Witnessing the builder in check-only mode
_campaign_builder_witness runs the real builder as a check-only subprocess when present, or falls back to the copied source-module manifest in the public clone, storing stdout and stderr hashes rather than bodies. The witness itself is _campaign_builder_witness. It looks for the builder named by BUILDER_REF at the repository root. When that file is present it runs it as a subprocess with --check --report --max-targets, with a 45 second timeout, and accepts the witness only when the process exits zero, returns kind standard_skill_pairing_campaign_summary, is not a no-op, reports at least one candidate target, emits a source_digest, and leaves wrote_packet unset. When the builder file is absent, which is the case in the public clone, it falls back to _public_source_module_builder_witness, which reads the copied source-module manifest and passes only when the target file's sha256 matches, its line count matches, and no required anchor is missing. Either way the witness stores stdout and stderr hashes, not bodies.
| Function | Role |
|---|---|
run, run_bounded_autonomy_bundle | Route the fixture and exported bundle through run_crown_jewel_organ with the shared evaluators |
evaluate | Load the three inputs, run the policy, witness, candidate, and digest checks, return findings |
_candidate_packet_subprocess | Convert the witnessed target count into stamped draft candidate rows |
_campaign_builder_witness | Watch the real builder in check-only mode, or fall back to the source-module manifest |
evaluate_negative_case | Mutate a copy of the input and re-run evaluate to confirm the refusal fires |
Module constants pin the boundary: EXPECTED_NEGATIVE_CASES maps mutations to codes, AUTHORITY_CEILING sets every autonomy flag false, and SPEC declares the required inputs, manifest ref, and anchors. The module constants pin the boundary. EXPECTED_NEGATIVE_CASES maps each named mutation to the error code it must produce. AUTHORITY_CEILING sets self_repair_authorized, unsupervised_source_mutation_authorized, source_write_packet_authorized, provider_calls_authorized, and release_authorized all to false. SPEC declares the required inputs, the source manifest ref, and the required anchors.
Diagram source & refs
flowchart TD Inputs["Public synthetic inputs coverage_gaps, campaign_policy, failed_campaign_digests"] PolicyGate{"policy allows write_source?"} Witness["Builder witness check-only builder run or source-module manifest"] WitnessGate{"reports candidates and wrote_packet unset?"} Draft["Draft candidate rows write_surface none, requires_human_review, source_mutation false"] DigestGate{"failed digest repeated?"} Refuse["Refuse source-write, blocked witness, or repeated digest"] Record["metadata-only result record refs, digests, stdout/stderr hashes"] Inputs --> PolicyGate PolicyGate -- "yes" --> Refuse PolicyGate -- "no" --> Witness Witness --> WitnessGate WitnessGate -- "no" --> Refuse WitnessGate -- "yes" --> Draft Draft --> DigestGate DigestGate -- "yes" --> Refuse DigestGate -- "no" --> Record Refuse --> RecordNegative cases
Refusals checked by mutating the input
The refusals are checked by mutating the input rather than trusting a declared label, as evaluate_negative_case copies the inputs, edits one file, and re-runs evaluate. The refusals are checked by mutating the input, not by trusting a declared label. evaluate_negative_case copies the required inputs into a temporary directory, edits one file, and re-runs evaluate.
The source-write policy case
The source_write_campaign_packet case appends write_source to the policy's allowed_actions and must produce BOUNDED_AUTONOMY_SOURCE_WRITE_FORBIDDEN. The source_write_campaign_packet case appends write_source to the policy's allowed_actions. It must produce BOUNDED_AUTONOMY_SOURCE_WRITE_FORBIDDEN.
The repeated failed-digest case
The repeated_failed_campaign_digest case duplicates a digest in the failed-digest ledger and must produce BOUNDED_AUTONOMY_REPEATED_FAILED_DIGEST, since an already-failed plan cannot be re-proposed under a fresh wrapper. The repeated_failed_campaign_digest case rewrites the failed-digest ledger to hold the same digest twice. It must produce BOUNDED_AUTONOMY_REPEATED_FAILED_DIGEST. A plan that has already failed cannot be re-proposed under a fresh wrapper.
Unknown negative cases fail with one stable code
Any negative-case id outside the declared set is rejected as unsupported with the stable bounded-autonomy error code. A negative case with any other id returns BOUNDED_AUTONOMY_NEGATIVE_CASE_UNSUPPORTED.
Prior Art Grounding
Preflight gating of proposed actions
The component follows established preflight-gate patterns from NIST AI RMF, Open Policy Agent, and GitHub Actions, applying that shape to draft self-proposals over synthetic public coverage gaps. The component follows established patterns for gating proposed actions before they run. The NIST AI Risk Management Framework frames AI work as governing, mapping, measuring, and managing risk rather than assuming autonomy is authorized. Open Policy Agent is a policy-engine pattern for deciding whether an action may proceed. GitHub Actions workflow syntax is a common automation surface where jobs and permissions are declared before execution. This component keeps the preflight-gate shape and applies it to draft self-proposals over synthetic public coverage gaps.
Validation Result record Path
What a pass means and how to route drift
A pass means both fixture and bundle drafted a packet, both negative cases fired their codes, and the record stayed metadata-only, with digest drift routed through microcosm_exact_copy_refresh. A pass means the fixture and bundle both produced a draft packet, both named negative cases fired their expected error codes, and the result record stayed metadata-only. If the source-module manifest reports digest drift, route that through microcosm_exact_copy_refresh; this page is not the authority for copied source bodies. If the full projection check fails because another session holds the shared lattice outputs, treat that as unrelated contention and use the corpus check as the local gate.
Scope boundary
Scope limit
The strongest supported claim is that under public synthetic inputs the component emits a draft self-proposal from a read-only witness and refuses source-write or repeated-digest inputs, both checked by mutation. The strongest claim the evidence supports is this: under public synthetic inputs, the component emits a draft self-proposal derived from a read-only builder witness and refuses a source-write policy or a repeated failed digest, with both refusals checked by mutating the input. That is the proof boundary and the scope limit for this module.
What the module does not claim
Context & evidence
In short Bounded Autonomy Campaign Packet validates public campaign packet fixtures: proposed gaps, policy gates, repeated-failure digests, negative cases, source-open body imports, and scope limits. It keeps campaign proposals separate from self-repair, source writes, live scheduling, external model access, launch-scope decision, public sharing, and whole-system correctness.
Scope limit Self-proposal campaign packet fixture and exported-bundle result record evidence only; no self-repair authority, unsupervised source-file changes, live scheduler authority, external model access, launch-scope decision, publishing-scope decision, or whole-system correctness.
Covers Bounded Autonomy Campaign Packet
Source
Source Source module: src/microcosm_core/organs/bounded_autonomy_campaign_packet.py · Design note · Source registry