Skip to content

SPEC-007 PR 4.5: subject producers, report-only - #721

Merged
cursor[bot] merged 12 commits into
masterfrom
cursor/spec-007-pr4-4.5-producers-69b9
Oct 8, 2026
Merged

cursor[bot] merged 12 commits into
masterfrom
cursor/spec-007-pr4-4.5-producers-69b9

Conversation

@IanFrelinger

Copy link
Copy Markdown
Owner

Summary

Production egress records for a self-extend cycle now name the agent. SelfExtendRunnerAdapter.RunAsync enters agent:<id> at SystemHigh around the cycle and the post-cycle admission and auto-share. ToolCallingAgent begins a read around each tool call. Only IEgressLabelledTool may report; RAGTool is the only labelled tool. A peer: chat response is observed as SystemHigh after it returns. A model response is not a read.

Still report-only. Nothing refuses, and no send changes. Records go from no-subject to subject:agent:<id> at SystemHigh.

This follows the merged 4.4 rule: a BeginRead scope observes only when it ends. Unreported or thrown is SystemHigh at dispose. A tool that reads and then egresses inside the same call, before the scope ends, is decided at the pre-read mark. That is a known limit for a runner whose floor is below SystemHigh. The production floor is SystemHigh, so the limit does not declassify self-extend. The owner can reverse it. Making an open scope count as SystemHigh would turn the leak's LevelTooLow into SystemHighData, because a mark only rises and a later Secret report could not lower it.

Changes

  • SelfExtendRunnerAdapter.RunAsync is the only production EgressSubject.Enter. Subject id is agent: plus the resolved agent id (the basis is subject:agent:<id>). Floor is new HighWaterMark(SecurityLabel.SystemHigh) because the snapshot carries unlabelled carry-over. The using is on the flow that enters it, covers the cycle, scratchpad, claim release, admission and auto-share, does not span a yield return, and is not inside an async helper. Overloads that only await RunAsync do not enter.
  • ToolCallingAgent wraps each tool invocation in EgressSubject.BeginRead. Complete runs only when the tool returns. A throw, including a refusal that throws, does not Complete, so dispose observes SystemHigh. Report is accepted only when the toolbox is a CapabilityRegistry and Find returns an IEgressLabelledTool. Otherwise the report is ignored and the scope stays unreported (SystemHigh).
  • IEgressLabelledTool.ReportRead is the public marker, recorded in src/Ashlar.Abstractions/PublicAPI.Unshipped.txt. It is an interface, not a default method on IToolbox (Ashlar.Abstractions is netstandard2.0). CapabilityRegistry.Find is the lookup.
  • RAGTool reports every outcome. Hits: trim the name, GetByName, require reference equality with one of DataSensitivityLevels.All, then ToDataLabel. Canonical names are the five primitives plus top-secret, any case, trimmed. A custom level, an unknown name, or an unmarked hit is SystemHigh. Zero hits, and the unrankable-query refusal, report Public ("read nothing"). Mapping stays in BackgroundAgents. No new production reference to AI.Pipeline.
  • EgressGuardChatClient keeps the 3-argument constructor. A second constructor takes the target key. UseAshlarGovernance passes it. A key that starts with peer: (trimmed, any case) observes SystemHigh after a successful response and after a fault. A synchronous throw (PolicyGate) is not observed. local: and cloud: are not reads. With no frame, observe is a no-op. The decision for the call itself is still the pre-response mark; the next decision sees SystemHigh.

Testing

Red first, on commit 11567292, before the wiring, filter EgressSubjectFloorPinTests|EgressSubjectProducerTests, net8.0:

Failed! - Failed: 6, Passed: 0, Skipped: 0, Total: 6, Duration: 312 ms - Ashlar.Tests.Infrastructure.dll (net8.0)

Green, on 4013b491:

Run Result
Producer facts, net8.0 Passed 26, failed 0, total 26
Producer facts, net10.0 Passed 26, failed 0, total 26
cert-gate, net8.0 Passed 2785, failed 0, skipped 0, total 2785
Ashlar.Tests.BackgroundAgents, net8.0 Passed 649, failed 0, skipped 1, total 650
Ashlar.Tests.BackgroundAgents, net10.0 Passed 649, failed 0, skipped 1, total 650
scripts/ci/run-repo-gates.sh all 26 gates passed

The skipped BackgroundAgents test is the suite's existing skip. DogfoodBlock8 and Prod_cli_objectives were not in these filters.

mutation drop-enter: KILLED red=failed:1/1 green=passed:1/1 ref=4013b4916c4b4db7aa4398ab5b99a2aa2062d9c5
mutation rag-read-nothing: KILLED red=failed:1/1 green=passed:1/1 ref=4013b4916c4b4db7aa4398ab5b99a2aa2062d9c5
mutation drop-labelled-marker: KILLED red=failed:1/1 green=passed:1/1 ref=4013b4916c4b4db7aa4398ab5b99a2aa2062d9c5
mutation peer-not-observed: KILLED red=failed:1/1 green=passed:1/1 ref=4013b4916c4b4db7aa4398ab5b99a2aa2062d9c5

A first drop-enter attempt did not compile (CS0161). mutation-check reported INVALID reason=red-no-tests. The kill above replaces the Enter with using (new System.IO.MemoryStream()).

dotnet was not run on the host. Cert-gate ran inside the container through scripts/test-in-container.sh.

Testing strategy (blast radius)

See Testing strategy pivot v1.

Change type Minimum proof (check what applies)
Infrastructure adapter (small / branchy) Not the change. Producers sit in BackgroundAgents and the chat client
Hosting / API / routing / barriers / AddAshlar Not touched
Megaclass (ProviderFactory, Docker provisioners, …) Not touched. The leak skeleton uses a fake model and a fake RAG store
  • Cert-gate net8.0 (2785 passed), producer facts on net8.0 and net10.0, BackgroundAgents on both TFMs
  • make kernel-coverage-gate (not run)
  • make kernel-gate (not run)
  • make test-prod-style (not run)

Not composed: the full EgressEnforcementLeakTests switch (4.11), MeaiBackedModel / AddAshlarMeaiPipeline, VectorDataRagService, enforcing mode, Bing, or redirects. Cert-gate was not re-run on net10.0. The full Infrastructure suite outside the certification filter was not run.

Checklist

  • Cert-gate passes in the devtest container (2785/2785 net8.0)
  • Documentation updated (SPEC-007, EgressInventory, CHANGELOG, cert-gate assertions)
  • No TODO or NotImplementedException left unresolved
  • Breaking changes are documented (records name the agent; still report-only)
  • Floor-pin cert-gate row. Certification count 133 .cs files, 136 entries
  • Public API unshipped line for IEgressLabelledTool
  • Knowledge graph regenerated after git add
  • Report-only. No new TSV row

Release

  • Not a versioned release — skip

Records for the drift audit

  • docs/EgressInventory.md — producers section and the within-call known limit. No new EG- id.
  • ci/egress-inventory.tsv — unchanged.
  • ci/cert-gate-assertions.md — floor-pin row; 4.4 "no production Enter" sentences now name this wiring; certification count 133 / 136.
  • docs/specs/SPEC-007-security-labels-and-reference-monitor.md — 4.5 status. Sibling bullets unchanged. No 4.4 merge SHA (that rides with PR 4.3).
  • CHANGELOG.md — [Unreleased] Added entry.
  • src/Ashlar.Abstractions/PublicAPI.Unshipped.txt — IEgressLabelledTool and ReportRead.
  • docs/knowledge-graph.json and docs/knowledge-graph.md.
Open in Web Open in Cursor 

cursoragent and others added 6 commits October 6, 2026 21:31
Cert-gate facts for the PR 4.5 floor, the Secret/Internal RAG leak skeleton,
an unlabelled tool, a throwing tool, and the production self-extend subject.
They fail until the runner, the read scope and RAGTool report.
Enter agent:<id> at SystemHigh around the cycle, begin a read around each
tool call, and let only IEgressLabelledTool report. RAGTool reports canonical
hit labels or Public when it read nothing. Peer chat responses observe
SystemHigh after they return. Still report-only.
The status bullet and the inventory used the placeholder until the pull request existed.
string.IsNullOrEmpty does not narrow a string? on that asset, so TryGetValue
was CS8604 and kernel-gate, uat, and readiness all failed the build.
…-4.5-producers-69b9

# Conflicts:
#	ci/cert-gate-assertions.md
#	docs/knowledge-graph.json
#	docs/knowledge-graph.md
#	docs/specs/SPEC-007-security-labels-and-reference-monitor.md
Co-authored-by: IanFrelinger <IanFrelinger@users.noreply.github.com>
@cursor
cursor Bot marked this pull request as ready for review October 7, 2026 22:57
cursoragent and others added 6 commits October 7, 2026 22:57
Co-authored-by: IanFrelinger <IanFrelinger@users.noreply.github.com>
Co-authored-by: IanFrelinger <IanFrelinger@users.noreply.github.com>
A_credential_holding_a_delimiter_reaches_no_record_field failed on Windows
when a random 64-bit Ref (e.g. 3017e74321a321bd) happened to contain the
digit credential piece 4321. Ref is not derived from the destination; skip
it in the payload substring scan like sequence/at.

Co-authored-by: IanFrelinger <IanFrelinger@users.noreply.github.com>
Co-authored-by: IanFrelinger <IanFrelinger@users.noreply.github.com>
Resolve cert-gate and egress convention conflicts by keeping PR 4.5
producer wiring and incorporating PR 4.3 redirect inventory/floors.
Regenerate knowledge-graph.

Co-authored-by: IanFrelinger <IanFrelinger@users.noreply.github.com>
Co-authored-by: IanFrelinger <IanFrelinger@users.noreply.github.com>
@cursor
cursor Bot merged commit 9b2ea56 into master Oct 8, 2026
55 checks passed
@cursor
cursor Bot deleted the cursor/spec-007-pr4-4.5-producers-69b9 branch October 8, 2026 02:56
cursor Bot pushed a commit that referenced this pull request Oct 8, 2026
# Conflicts:
#	docs/knowledge-graph.json
#	docs/knowledge-graph.md

Co-authored-by: IanFrelinger <IanFrelinger@users.noreply.github.com>
cursor Bot pushed a commit that referenced this pull request Oct 8, 2026
Co-authored-by: IanFrelinger <IanFrelinger@users.noreply.github.com>
IanFrelinger pushed a commit that referenced this pull request Oct 8, 2026
095ba46 (six lenses + synthesis), filed with the paused phase C handoff
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants