Error transparency and permissions audit

Dated design and evidence record. Selected design and evidence quotations retain their source line anchors and historical identities; use the current guides for operation.

# Error transparency and permissions audit

Read-only audit of this repository, 2026-10-20 16:47–16:56 UTC.
Source checkpoint: 127aef7; diagnostic projection unchanged from the tested image.
Runtime probes used installed controller image
sha256:129a218bf8d5ce9665f049ef5fd9e0112028c4adfb0b350385be5d01b4c24c96,
network none, read-only root, UID 65532, no capabilities, bounded resources.
Permission probes used synthetic files in a private temporary container filesystem.
No real credentials, model calls, API changes, source edits, or permission changes.

## Reproduced error losses

1. process_reports.py::failure_evidence omits ExchangeFailed.response_head and
   ChatFailed.reason. A received HTTP 429 plus x-request-id followed by timeout
   renders only ChatFailed/ExchangeFailed/TimeoutError, losing both received facts.
   Requested fix: reviewed status/correlation projection; no raw header/body dump.
2. PreparationRetirementFailed(operation_failure=InputRejected(message,
   diagnostic=...), cleanup=EIO) renders the message and EIO, but drops the native
   reader diagnostic. Cleanup prevents ordinary AnalysisFailure persistence.
3. Two ToolConversation endpoints failing request-limit then HTTP 503 leave two
   entries in endpoint_failures, but the propagated exception report contains only
   the second cause. Successful fallback retains reason/status in public routes,
   not the earlier protected cause. Preserve safe endpoint evidence through an
   existing boundary, without transcripts or a new journal.
4. Reviewed AllocationUnconfirmed, RetirementUnconfirmed and ExecutionRefused
   render as bare class names. Their safe absent/malformed/unconfirmed-receipt
   reasons disappear. Further source review identifies ResultRejected and other
   binding outcome classes missing from the explicit projection inventory.
5. process.py::_failure_report writes stderr before trying _publish. A synthetic
   BrokenPipeError at stderr prevents failure.json publication even when the file
   sink is available. The independent outputs must both be attempted.
6. The service proxy projects DNS owner-created OSError reasons with errno=None
   as just OSError; errno=None, losing NXDOMAIN rcode, truncated reply, and
   mismatched-question distinctions. Preserve reviewed protocol reasons at owner.

## Additional concrete scenarios sent for verification

- Cancellation during a model POST bypasses ChatFailed wrapping and can strand
  HttpTransport.last_failure evidence; requested service cancellations are skipped
  by ProviderService::_record_task_failure. Test real process shutdown after
  response headers and with nested cleanup causes. An intentional stop need not
  become a failure, but known causes/effect uncertainty must survive.
- StartFailed.acknowledgement and PublicationFailed.outcome are retained internally
  but their receipt-presence facts are absent from the operator projection.
  Distinguish received-but-not-durable from no verified response without dumping
  records or claiming a new lifecycle authority.
- Review safe ResultRejected, ConformerShortfall/ConformerOutputLimit,
  ModelReportedInputProblem and UploadInputRejected when cleanup prevents their
  ordinary outcome/evidence path. Do not dump partial coordinate collections.
- Proxy 403 becomes a bare httpcore.ProxyError on the controller side. The proxy
  owns the safe refusal log; verify correlated operator access to both surfaces.

## Preliminary permissions evidence

- config.py::read_startup_file: synthetic secret modes 0400/0600 accepted;
  0640/0644/0660/0666 refused. Both API signing artifacts and interpreter keys use
  this secret path; opened descriptor owns UID/mode admission, not a pathname stat.
- process.py diagnostics: private directory 0700 and final file 0600 under umasks
  000, 022 and 077. AttemptFiles similarly requires root 0700 and records 0600,
  same UID, single link; it uses descriptor-relative exclusive publication.
- Installed /opt/provider: zero group- or other-writable entries.
- Three current native-service receipt trees (TMRiIqjV, wMwkAIMq, P3INGwm9): zero
  group/other permission bits on any retained entry.
- No world-writable or set-ID entries found in maintained checkout paths outside
  .work, .git and the upstream submodule. No set-ID entries found in .work.
- Full .work scan found 21 world-writable old qualification scratch entries from
  Oct 14–15 (formatted source copies/output directories). The private home ancestor
  is 0700, with no extended ACL grants on inspected roots. Do not present these old
  public fixture copies as a demonstrated credential exposure or blanket-chmod
  an active shared tree.
- provider_workers_open under umask 000 creates root 0700 but child requests,
  receipts, ipc and owned directories 0777. Existing service qualification sets
  umask 077. Production launcher must establish the private creation contract;
  a bind-mounted child must be assessed in its receiving namespace, not assumed
  protected by the host-only ancestor.

## References at source checkpoint 127aef7

These locations refer to commit 127aef7, not moving line numbers during repairs.
The synthetic probes used the installed image built from 9bb0783; the relevant
diagnostic projection was unchanged at 127aef7.

- nmrnet_provider/process_reports.py:60,105,162: explicit cause relationships,
  reviewed owner summaries, bounded private receiving renderer.
- nmrnet_provider/process.py:221: stderr/file report publication ordering.
- packages/provider-core/src/provider_core/chat.py:72,136: private carrier
  failure fields and completion/interruption boundary.
- packages/provider-core/src/provider_core/conversation.py:71,153: conversation
  owner and retained per-endpoint failures; _run selects the final cause.
- nmrnet_provider/service.py:255: requested task-cancellation observation.
- nmrnet_provider/allocation.py:25 and retirement.py:21: reviewed host allocation
  and retirement reasons omitted from the original receiving projection.
- nmrnet_provider/result.py:62: reviewed scientific result-admission reasons.
- nmrnet_provider/smiles.py:55 and smiles_protocol.py:56: shortfall/output-limit
  evidence that normally follows the AnalysisFailure path.
- packages/provider-core/src/provider_core/starting.py:27 and publication.py:25:
  received acknowledgement/outcome retained alongside independent storage failure.
- tools/provider_proxy.py:34: native failure projection; tools/bound_http_proxy.py
  _query_ipv4 and resolve_ipv4_bound: DNS protocol failure creation and aggregation.
- nmrnet_provider/config.py:212: descriptor-based startup ownership/mode checks.
- packages/provider-core/src/provider_core/attempt_files.py:99,147,289: private
  store-root admission, record admission and exclusive durable publication.
- tools/provider_workers.sh:10: private root versus inherited child creation modes.

Observed native-service receipt directories:
.work/qualification/provider-service-nmrnet-native-service-TMRiIqjV
.work/qualification/provider-service-nmrnet-native-service-wMwkAIMq
.work/qualification/provider-service-nmrnet-native-service-P3INGwm9

Representative old world-writable scratch entries (metadata only; not consumed
as trusted runtime configuration in this audit):
.work/qualification/native-returned-diagnostics-20261015/formatted.py (0666)
.work/qualification/explicit-launcher-presence-20261014/outputs (0777)

## Repair checkpoint, 2026-10-20 17:03 UTC

Peer reports that new receiving tests cover missing owner reasons, native input
diagnostics, received-but-not-durable receipt facts, broken stderr with working
file output, and both outputs failing. These edits remain uncommitted at this
checkpoint and have not yet been independently revalidated by this auditor.
Endpoint-history and interruption-evidence handoffs are still being implemented.
Do not treat the original findings as verified repaired based on acknowledgement.

## Independently qualified receiving repair, 2026-10-20

The first repair closes reproduced findings 1, 2, 4 and 5 in current source.
The correlation helper moved unchanged from api.py::_header_request_id to
transport.py::response_request_id, reused by API and operator projection.
The renderer reads current ChatFailed/ExchangeFailed response metadata, admits
one bounded correlation ID, includes the owned chat reason and excludes all
other headers/body/notes. InputRejected's native diagnostic uses the existing
redact-before-head/tail window, alongside its primary and independent cleanup.
The exact-owner inventory now includes allocation/retirement and lifecycle
refusals, ResultRejected, shortfall/output-limit/model-reported input summaries,
UploadInputRejected and CredentialRejected's original parser cause. Serialized
scientific replies, partial coordinate arrays, model explanation/observation
and arbitrary native exception messages remain excluded from this projection.
StartFailed reports acknowledgement presence and observed Attempt state;
PublicationFailed distinguishes a received observation, matching commit receipt
and reviewed conflict. These facts establish neither durable storage nor reuse.

Both protected report outputs are attempted independently. Broken or closed
stderr does not prevent file publication. Reporting failures join the original
operation/cleanup causes; both failed sinks raise the owned aggregate. The held
process's existing finally still retains its work/store. A real child fault
witness verifies both errno causes, held process/store, absent forbidden cleanup
and release only after exact parent kill. The extra child marker is test-only
observation, not another production diagnostic sink or journal.

Qualification: coordinator and independent authority reviewer each ran
make test/integration/provider-core/process: 32 tests passed (independent run
17.721 seconds). Tests receive actual stderr plus failure.json and exercise
real signed local API/process shutdown; no external model or scientific native
execution was needed. Selected-file Ruff check/format and Bash syntax passed.
Independent authority/provenance inspection found no remaining signal in
this subset. Local logs: /tmp/nmrnet-transparency-receivers-final.log and
/tmp/nmrnet-independent-reports.log (ephemeral; maintained tests are the proof).
The installed image quoted above is the original audited artifact, not a claim
that it contains this source repair; refreshed image qualification remains due.

Still open: finding 3 (endpoint history), finding 6 (DNS protocol reasons),
interruption/effect handoff, joint proxy/controller operator access and production
creation/mount permissions. Existing permission observations remain observations
from the original audit; no historical scratch permissions were changed.

## Independently qualified DNS repair, 2026-10-20

Finding 6 is now qualified in current source. The existing DNS response/name
decoders create exact owner-typed refusals from a fixed reason vocabulary;
the response code is the parsed four-bit numeric field. OSError/ValueError catch
contracts and DNS/parser ordering remain unchanged. Service diagnostics render
only those exact owned reasons; arbitrary native errors remain type/errno only.
No remote name, resolver address, packet bytes, exception note or request header
is rendered. Alias-cycle text no longer interpolates the destination hostname.

Four binary-packet witnesses exercise real _query_ipv4 -> resolve_ipv4_bound ->
ServiceProxyHandler receiving output: rcode3, short response, wrong question and
truncated compression pointer. Only UDP I/O, resolver inventory, transaction ID
and time are injected. Each verifies the owned reason, fixed 502, one closed UDP
exchange, no destination TCP allocation and absence of private packet/request
canaries. Coordinator and independent provenance reviewer each ran
make test/unit/provider/proxy: 60 tests passed, including all selected acquisition
and proxy-posture regressions. Independent code/provenance source review found
no further signal; selected-file Ruff/format and existing guard scans passed.
Ephemeral independent log: /tmp/nmrnet-independent-dns.log.

Endpoint history, interruption/effect handoff, joint operator access and the
production host creation/mount contract remain open. This protocol-diagnostic
repair does not establish external DNS/network reachability or deployment.

## Useful private diagnostic correction, 2026-10-20

Review of df951d0 found that the first scientific/model cleanup tests wrongly
treated useful private diagnostics as secret canaries. Safe summaries alone
did not preserve the reason normally retained by session._failed_preparation.
That first checkpoint was therefore incomplete for these cleanup scenarios.
Current source projects ConformerShortfall.partial.diagnostic, only the native
diagnostic text from ConformerOutputLimit's serialized reply, and the model's
explanation through the existing redact-before-head/tail window. Model explanation
remains explicitly unverified on the protected operator surface. Coordinates,
stereochemistry, raw provenance and observation/transcript bytes remain excluded.

The receiving regression now requires useful native/model text, native tail and
omission facts, alongside independent cleanup EIO. Configured-key spellings,
Bearer/key-field canaries are redacted; a PRIVATE_* prefix is not itself a secret
classification. Coordinator and independent provenance reviewer each reran
make test/integration/provider-core/process: 32 passed (independent 16.017s).
Independent authority/provenance source review found no further signal in this
correction. Fresh log: /tmp/nmrnet-independent-private-diagnostics.log.

The adjacent DNS simplification keeps the two exact disclosure-owner exception
types and direct code-owned English at each raise. The unused reason-code table
and attributes are removed; only the parsed numeric rcode is interpolated.
The existing binary-packet witnesses and full focused proxy lane still pass
(60 tests). No new abstraction or routing behavior was introduced.

The permission probes above are preliminary. The requested full permissions
audit remains due after the transparency repairs; production creation/mounted
subtree qualification is still open. Historical scratch was not blanket-chmodded.

## Endpoint-history failure handoff, 2026-10-20

The core now transfers its indexed original endpoint failures on final failure,
cleanup failure and successful conversation return. A foreign scientific/tool
failure keeps its exact exception identity and prior explicit cause through an
owned context; no successful tool is repeated. The operator graph deliberately
traverses these owned indexed causes under its existing 64-node bound.

The maintained process receiving test uses real local TLS ChatEndpoints: endpoint
0 rejects an oversized request without sending it, then endpoint 1 receives HTTP
503. Both stderr and failure.json retain both reasons, received status and the
reviewed request ID, excluding Job content, response body, other headers and
keys. The focused process lane passes 33 tests; core chat passes 27, including
fallback followed by exact cancellation with its original earlier cause and no
extra dispatch. Independent source review identified an installed-test namespace
mistake, corrected before the passing run; no remaining source signal reported.
Ephemeral logs: /tmp/nmrnet-endpoint-history-receiving-final.log and
/tmp/nmrnet-endpoint-history-core-final.log.

This closes the terminal-failure history loss. Successful history is handed off
by core but its binding/durable evidence retention remains the next repair.
Interruption during a handed-off POST and the full permissions/launcher work
remain open. This source result does not update the previously quoted image.

## TLS fixture lifetime qualification, 2026-10-20

The history receiving/service checks exposed a fixture lifetime gap: asyncio
accepts TLS handshakes before TlsPeer.handle registers its task. A real ClientHello
observed by the SNI callback, with no completed handshake or HTTP handler, made
the existing two-second server teardown fail. The fixture now supplies explicit
0.5-second TLS handshake/shutdown deadlines inside that observation budget and
closes late handler entrants. After accepted transports close, it gathers the
final handler set so a late handler's failure is also observed by its owner.
It does not widen the teardown deadline or alter
production transport budgets. The new adversarial packet/handshake witness went
red before the correction and green after it; the chat lane passes 28 tests.
Logs: /tmp/nmrnet-tls-handshake-fixture-red.log and
/tmp/nmrnet-tls-handshake-fixture-final.log.

This proves retirement of an admitted incomplete test-peer handshake. A separate
intermittent service Hello retirement failure was not causally established by
its original wrapper-only trace. One scratch receiving-renderer diagnostic run
of that unchanged test stopped cleanly, with HTTP200 plus cancellation retained
on the API/transport owner and no cleanup failure. This is evidence for the
still-open interruption-reporting work, not proof that the earlier failure had
the same cause. No production deadline was relaxed or retry added.

## Successful fallback evidence retention, 2026-10-20

Before each scientific tool dispatch, the interpreter projects original indexed
endpoint failures using the existing configured-key-aware operator renderer.
Immutable private bytes stay on InputPreparation, outside public interpretation.
NMRNetSession includes them in its prepared identity under the existing total
ProtectedEvidence capacity gate, before prediction preparation, then carries them
into terminal success or recognized scientific/model failure evidence. An evidence
overflow refuses prediction and retains the complete attempted evidence; it is
not truncated, retried or called invalid input. Model-report cleanup can also
traverse original endpoint causes without disclosing transcript/body content.

Connected local TLS witnesses cover request-limit -> HTTP503 -> successful
SMILES preparation, exactly one generation and prediction, private terminal
retention, unchanged public result, and fresh-store recovery of execution entry
after an injected stop before prediction. All four model-report guidance cases
also retain prior endpoint causes while reaching the original failure recipient.
These are scripted model replies, not real semantic-interpreter qualification.

Focused contained lanes pass: service 22, prepared-identity 31, interpreter 18.
The identity lane exposed two older API fixtures using generic unmarked TLS
responses. Independent scratch reproduction traced both failures to the exact
missing Nmr-Api-Topology response marker. Those fixtures now use the existing
api_tls_peer; production envelope admission remains strict. Source review found
no further ownership/privacy signal. Logs: /tmp/nmrnet-success-history-service-qualified.log,
/tmp/nmrnet-success-history-identity-qualified.log,
/tmp/nmrnet-success-history-interpreter.log and
/tmp/nmrnet-independent-identity-causal.log (ephemeral).

Interruption during a handed-off POST, full permissions audit and the connected
production launcher remain open. Previously quoted installed image is stale;
source-level qualification does not update or qualify that artifact.

## Model interruption and nested operation evidence, 2026-10-20

ChatEndpoint now attaches its owned interrupted-request context to the exact
caller cancellation, preserving the live transport failure and any previous
explicit cause. Transport's original primary may be that same cancellation;
the protected graph deliberately represents this cycle with exception references.
InputPreparation preserves a distinct chooser failure when joining after an outer
failure, on both clean and failed retirement. A bare expected child cancellation
remains an ordinary stop. A settled operational child error keeps its original
object and diagnostic; successful joining is not called retirement failure.

AttemptExecutor captures child cancellation inside the actual coroutine, before
Task.result can consume it. Its existing owned failure is now updated in place,
so escaped references receive late operation evidence and independent cleanup
observations. Caller cancellation remains primary through cleanup cancellation;
an ordinary/API primary remains reachable when cleanup cancellation propagates.
Session retirement retains the cancellation's earlier owned cause, and controller
settlement no longer clears that chain. Service suppresses only bare requested
cancellation and records initiating failures before shutdown-induced observations.

The real foreground witness receives a model response head, then SIGTERM. Both
protected operator outputs retain HTTP200, the reviewed request ID and an explicit
statement that the model request may have been processed. One model POST, zero
prediction/source effects, no terminal send and no resend are required. With
independent host-retirement EIO, the process stays alive and its actual store
stays locked until exact parent kill. Native allocation is a recording test port;
the interpreter, TLS/CONNECT, input owner, controller, signals, store and process
reports are real. This does not qualify a production native launcher or external
model interpretation. Ordinary idle SIGTERM still exits zero.

Focused contained results: process 35; core chat 29; core prepared-identity unit
68; service 22. These include the actual receiver for nested model diagnostic plus
cleanup cancellation and exact canonical-record recovery after a timed-out child
join. A later user finding exposed non-cancellation WorkerReportedFailure after
parent cancellation: the corrected fixture reproduced the absent parent cause,
then the narrow condition repair passed all 19 interpreter tests. That witness
also receives stderr and failure.json, requires the useful worker reason, redacts
credential-field text and requires no retirement failure after a clean join.
The first attempt had a fixture constructor error; it was not behavioral proof.
Logs: /tmp/nmrnet-interrupted-model-receiving-final.log,
/tmp/nmrnet-interruption-executor-final.log, /tmp/nmrnet-interruption-chat.log,
/tmp/nmrnet-interruption-service-final.log, /tmp/nmrnet-operational-child-red-final.log
and /tmp/nmrnet-operational-child-qualified.log. Independent source audits found
no remaining signal in this subset. An independent sequential rerun also passed
process 35 (22.142s) and interpreter 19 (0.393s); no lane containers remained.
Independent logs: /tmp/nmrnet-independent-interruption-process.log and
/tmp/nmrnet-independent-interruption-interpreter.log. These still use recording
native/fault ports; they do not establish real native cleanup or image freshness.

Still open: expected Hello cancellation retains API evidence on its API owner
but does not yet reach the final process recipient. The planned narrow follow-up
retains it as a protected shutdown observation, separate from failures deciding
exit/release; received headers must not imply verified Hello acceptance. Full
permissions qualification and the connected production launcher remain due.
The earlier installed image remains stale until rebuilt and qualified.

## Expected Hello interruption reaches shutdown output, 2026-10-20

The service retains the original dedicated Hello API failure when its requested
task cancellation interrupts an actual request. This single observation does not
change success/failure or release decisions. After confirmed retirement, the
existing protected result.json includes reviewed status/correlation/cause evidence
and acceptance_confirmed=false. HTTP200 headers are not a verified HelloAccepted
body. If an independent failure requires failure.json/stderr instead, that same
observation joins the existing report only after exit/release decisions. No new
journal, protocol, replay or lifecycle authority is introduced.

The real foreground witness completes startup Hello, then receives headers for
the second periodic Hello and signals SIGTERM. A child-only received-head number
gives a distinct barrier, avoiding a delayed parent erasing the periodic marker.
The process exits zero with the protected observation, empty reopened store and
exactly two Hello sends. A separate adversarial result-publication EACCES witness
requires the Hello observation and write error in both stderr and failure.json,
exit one, confirmed resource release and no extra send. The API peer and private
CONNECT route are real local TLS; only the fixed head marker and optional result
write failure are injected. This is not deployed API/GUI proof.

The old source reproduced a missing interrupted_hello field on that actual clean
stop. Focused process qualification now passes 37 tests (27.189s); selected-file
Ruff check/format and whitespace checks pass. Independent code review found the
initial shared-marker race; the numbered barrier and failure-output witness
correct it. Independent authority/privacy and code reviews found no remaining
signal. The independent process rerun also passed 37 tests (27.482s), with no
lane containers left. Log: /tmp/nmrnet-independent-hello-observation.log.
Logs: /tmp/nmrnet-hello-observation-red.log and
/tmp/nmrnet-hello-observation-final.log (ephemeral).

The reproduced error-transparency repairs are now implemented in source, with
the receiving checks above. The installed controller image still needs refresh;
full permission probes and production host creation/mount qualification remain
open. Preliminary modes from the original artifact are not current-image proof.

## Refreshed controller and full permission audit, 2026-10-20

The controller was rebuilt once after the error repairs at source 1131107:
sha256:62eb7abc76846b404b194432080d946d9dcd2670dce5538349d9e2966909a675.
The build succeeded and .work/provider/image-id identifies that artifact. The
focused installed-runtime lane passed four tests. Build/runtime logs (ephemeral):
/tmp/nmrnet-provider-repaired-image-build.log and
/tmp/nmrnet-provider-repaired-runtime.log. Independent final source rerun at
1131107 passed process 37, interpreter 19 and proxy 60; report supplied by the
foreground auditor, /tmp/nmrnet-monitor-errors-final-20261020.log. Scientific
accuracy witnesses were not repeated for these diagnostics-only repairs.

Independent foreground audit on that refreshed image reports: secret modes
0400/0600 accepted, 0640/0644/0660/0666 refused; diagnostic directories 0700 and
files 0600 under umasks 000/022/077. /opt/provider has zero group/other-writable
entries; an attempted runtime-root write fails EROFS (30). Through an actual
read-only bind grant, caller UID:GID 1000:1000 can read a synthetic 0600 key but
cannot write it (EROFS). UID 65533 with the same GID 1000 receives EACCES (13)
on read and write. No real credentials were used. The production caller must
explicitly select the admitted file owner's UID/GID; the image default UID 65532
is not a reason to weaken same-EUID or credential-mode checks.

Read-only metadata inspection at 1131107 found 533 maintained tracked regular
files excluding the upstream/.git trees, all caller-owned/single-link, without
maintained-tree symlinks, set-ID, world-writable files or extended/default ACLs.
The 79 provider capture roots contain 191 private directories and 1041 files:
891 mode0600, 150 mode0664 metadata markers behind private directories. The 12
service captures specifically contain 434 files0600 and 124 directories0700.
A native-capture snapshot contains 83 files0600 and 35 directories0700. No
unexpected links, special files, set-ID or ACL grants were found in those
captures. Counts are observations of changing qualification outputs, not a
permanent inventory. The foreground auditor additionally inspected upstream
and .git: no world-writable/set-ID entries, and recursive getfacl --skip-base
across .work/.git/upstream found no extended ACL grants. No credential-named
files were found in .work; this is a filename observation, not a secret-content
scan. No credential contents were read by these metadata probes.

The earlier 21 world-writable public-fixture scratch entries remain: ten files
and eleven directories. A symlink's displayed 0777 is not evidence about its
target. Private ancestor traversal prevents demonstrated cross-UID exposure
here. These observations do not authorize blanket chmod or historical deletion.

The remaining creation defect was reproduced using actual provider_workers_open
under umasks000/022/077, without engine dispatch: its allocation root is0700 but
requests/receipts/ipc/owned are respectively0777/0755/0700. Role directories and
create-intent likewise inherit the mask. A worker's later umask cannot repair
an existing bind root; its host ancestor is absent in the receiving namespace.
The qualification caller already uses077. Fresh host creation needs an explicit
private contract, followed by actual production caller UID/mount qualification.
Synthetic reproduction retained under /tmp/nmrnet-permission-open.fMNR3VZu.

Independent artifact/mount probe confirms the image input label
sha256:5963a602de5e9bb50e8d3405c4a9b5801a6caea7c4a1bbb6266ef8cd640e5c61,
matching committed controller inputs at113110723085a730e2f442afec4e7296e4aa4d52.
It inspected /opt/provider, /usr/local/bin, /usr/local/lib, /usr/lib and resolved
symlink targets:3629 entries,96 symlinks; zero g/o-writable, set-ID, non-root-owned,
broken or unreadable entries. Image user65532:65532, isolated process entrypoint,
no declared volumes/ports or unexpected environment names; values not displayed.
The only key/config filename candidate was certifi's public CA bundle. Six actual
read-only grant mutation probes failed EROFS; intended Unix-socket communication
succeeded. CallerUID1000:GID1000, networknone, zero capabilities, no-new-privileges,
2CPU,512MiB/no swap,64PIDs were observed. The old separately mounted receipts root
retained0777 in its receiving namespace, confirming the host-creation finding.
Report (ephemeral): /tmp/nmrnet-provider-permissions.8mI39ttH/report.json,
SHA2563a660c45064f8bc2427eedd40297ac9a048a36e15f28d74317257856e6b68550.
Both exact probe containers were removed; ownership-filtered inspection was empty.
These are artifact/component proofs using synthetic grants, not production
launcher proof or whole-image secret-content forensics.

Fresh host-creation repair: provider_workers.sh now creates its bind roots,
role/diagnostic/IPC directories and both receipt branches with explicit0700;
create-intent uses scoped077. It neither changes the caller's mask nor modifies
retained history. The maintained make test/unit/provider/allocation witness
reproduced requests0777/0755 under000/022 before the repair; all23 tests then
passed, including all three masks, live IPC permissions before removal, retained
files0600/directories0700, unchanged caller mask, no-allocation retirement receipt
and unchanged six exact modeled engine calls. This tests actual host Bash with
a recording engine, not real container grants or native science.
Logs: /tmp/nmrnet-allocation-permission-red.log and
/tmp/nmrnet-allocation-permission-final.log. A production caller must still set077
before its own unrelated host creation and prove its actual mounted grants.

The installed-image owner probe exercised30 startup,15 diagnostic and27 store
state/fault/reopen cases under000/022/077. It imported production modules only
from the installed environment. Temporary synthetic ownership setup occurred
only in tmpfs; the actual calls ranUID1000 with zero capabilities, networknone,
read-only root,512MiB,2CPU,64PIDs. Report (ephemeral):
/tmp/nmrnet-permissions-installed.aIp4EAln/output/report.json;
log /tmp/nmrnet-permissions-installed-audit-verified.log. Its exact container was
retired. Startup checks covered link/FIFO/directory/foreign-owner refusal and
nonsecret writable input; diagnostic checks included partial publication faults;
store checks included retained state, write faults and reopening.

That probe found one additional creation gap: process._publish's default open
creates0666/0644 under000/022 before its fchmod. A failing fchmod leaves only an
empty broad-mode pending file under its0700 parent: no diagnostic bytes were
written, and no credential leak was demonstrated. The cached refreshed image
reproduced exactly0666/empty under000 in
/tmp/nmrnet-pending-permission-red.log. The source repair supplies0600 atomically
through built-in open's descriptor opener, preserving exclusive creation and
the existing with-block close owner. fchmod remains to normalize more restrictive
ambient masks before writing; there is no raw-descriptor transfer framework.
The new receiving regression injects that exact failure under000/022/077,
requires the original exception, empty0600 staging and no final file. The focused
process lane passes38 tests (27.797s), including existing independent-sink and
held-store witnesses. Selected-file Ruff and whitespace checks pass. Source-only
authority and provenance audits found no additional signal. Log (ephemeral):
/tmp/nmrnet-pending-permission-final.log. This small source correction awaits the
next coherent image refresh; the1131107 artifact above truthfully still has its
reproduced empty-staging defect.

The final installed-owner audit extended store coverage to42 cases (rather than
the earlier27), including wrong root/record modes, actual foreign ownership,
link/hardlink/FIFO/directory refusal, and root-owned public startup input.
Report: /tmp/nmrnet-permissions-storage.qWy7vXOD/output/report.json;
log /tmp/nmrnet-permissions-storage-audit.log. Earlier synthetic setup failures
retired before production-owner calls and are not qualification evidence.

Installed repair qualification after the coherent startup-capture build:
source9b9c347, image
sha256:cf5d5ca374b2c5dbd21db44a5a201a4d54f731add22c5c585a8bccacfdc4b741.
The installed process.py SHA256
76fd951484b2acabcbbccf29a638f62bf1048edc942ba06e400d6c7e67fe67ab
matches source. Six independent cases exercise normal publication and injected
fchmod-EIO under000/022/077: normal exact bytes0600 with no pending alias;
the identical EIO object escapes, leaving only empty0600/currentUID/nlink1 pending
and no final file. UID1000, capabilities0, read-only root, networknone, no-new-
privileges,2CPU,256MiB/no swap,64PIDs; only a synthetic read-only probe script and
private tmpfs were granted, without source/test ports, state or native grants.
Exact container wait returned0, stopped inspection was confirmed and removal
completed. Evidence: /tmp/nmrnet-installed-publish.zSlzD2jm/start.stdout and its
adjacent posture/retirement receipts; log /tmp/nmrnet-installed-publish-fault.log.
The four installed-runtime tests additionally pass on this image (0.733s),
including imports of the actual capture/proxy modules. Logs:
/tmp/nmrnet-startup-capture-image-build.log and
/tmp/nmrnet-startup-capture-installed-runtime.log. The unchanged full permission
and scientific matrices were not repeated; production launch grants remain open.

## Limits and follow-through

These are local source and installed-renderer checks. They do not qualify a real
external interpreter or deployed API/GUI recipient. The production host launcher
is still being connected. Peer implementation and regression results remain to
be reviewed; notification is not proof of repair. Continue monitoring.

## Actual foreground/API run observation, 2026-10-21T21:00Z

Qualification source bb15cf2676525cc605949e2431b741a2ff9a616d, installed controller
sha256:5b40da88e76255b3761a21386a3aa5135aac9c82fb165f8eb106ed20bce05bea.
The first complete successful actual-API witness is detailed in003 R21, with
retained capsule .work/qualification/provider-api-pasted-20261021-2100.
Independent read-only reviewers inspected the actual captured metadata and exact
retirement receipts; no real keys were read or effects rerun during that review.

All ten container IDs (peer, stage, public client, capture/controller/three routes,
reader and prediction) have stopped/removal receipts. Captured posture establishes
caller UID/GID1000, readonly roots, dropped capabilities and no-new-privileges.
The peer has only fixed fixtures/public model output/diagnostics; real provider and
client credentials appear only in their separate readonly grants. Successful
startup/Hello also exercised the real descriptor-based credential UID/mode admission.
Private native, state, source, component, route and output trees have no group/
other permission bits. Public source-code capture copies are0644/0755 under0700
ancestors; these are code, not credential material. No blanket chmod was performed.

The process's protected result says stopped/requires_host_retirement=false and
retains an interrupted Hello's acceptance-unconfirmed cause. The actual accepted
AnalysisResult is independently verified through signed public readback. This is
connected evidence for error/effect separation, not a new lifecycle authority.

Limit: helper postures enumerate mounts; controller/native posture receipts rely
on the existing source-owned mount argv and fixed profile checks rather than an
independent full live mount enumeration. This run supplies positive production
creation/credential-admission evidence for one caller UID; it does not repeat or
replace the earlier synthetic denial/foreign-UID/EROFS/ACL matrix, prove deployment,
or qualify every future environment. Original private paths/state remain outside
version control; the compact receipt archive explicitly excludes key contents.

## Corrected interpreter rejection evidence, 2026-10-22

Repair commit af63281 retains correction evidence that corrected selections
previously lost. Before the repair, ToolConversation counted a rejected tool
turn and kept its last safe feedback text, but discarded the caught ToolRejected
object. A later accepted selection therefore lost that reason and the chained
InputRejected's private parser diagnostic from the retained interpreter evidence.
The new focused tests reproduced the missing history before implementation.
This keeps the reason for an input change available to an operator after
selection succeeds, under the existing model-feedback and scientific-effect policy.

ToolConversation now retains (one-based turn number, ToolRejected) entries within
the existing total model-turn limit. Original dispatch rejection objects and
their causes survive corrected success, exhausted turns, later operational
failure, cancellation and independent connection-cleanup failure. The primary
failure and cancellation objects retain their identity and earlier causes.
Multiple-call refusals retain the conversation owner's safe typed reason.

InputInterpreter combines earlier endpoint failures and correction failures in
the existing private interpreter_diagnostics capability before invoking the next
preparation tool. The session regression uses installed provider-core and current
NMRNet source, a failed endpoint, a reader rejection and then one successful
generated-input preparation. It checks that the safe reason and bounded,
credential-redacted parser diagnostic are present before generation and survive
prepared/result evidence. The public
interpretation exposes the correction count, with no correction reason, parser
dump, model transcript or raw tool arguments added. A final model problem report
also retains the earlier correction evidence privately. The process renderer
admits the exact ToolRejected safe message and traverses correction histories,
including an exhausted conversation followed by independent cleanup failure.

Focused contained qualification passed: make test/integration/provider-core/chat
(31 tests), make test/integration/provider-core/interpreter (24 tests), and
make test/integration/provider-core/process (39 tests). Ruff 0.15.15 lint/format
passed for the seven changed Python files in the recorded offline checker image;
Bash syntax and diff whitespace checks passed. The interpreter selector now names
its interpreter/preparation test files explicitly: the previous wildcard also
collected ambiguity tests without their separately owned fixture mount, causing
two reproduced ModuleNotFoundError failures unrelated to correction retention.

References fixed at af63281:

- packages/provider-core/src/provider_core/conversation.py::ToolConversation.run,
  _run, _retire_endpoint and retire; ConversationResult/ConversationFailed/
  ConversationRetirementFailed carry the private correction history.
- nmrnet_provider/interpreter.py::InputInterpreter.run and
  ModelReportedInputProblem; process_reports.py::_owned_relationships and
  _safe_owner_details; tools/container.sh's interpreter test selector.
- packages/provider-core/tests/integration/chat/normative/test_conversation.py::
  test_corrected_success_retains_original_rejection_without_public_reason_or_arguments;
  adversarial/test_conversation.py::test_prior_correction_survives_exhaustion_operation_failure_cancellation_and_cleanup.
- tests/integration/provider_core/adversarial/test_nmrnet_interpreter.py::
  test_corrected_reader_rejection_keeps_private_diagnostics_and_prior_endpoint_failure_before_generation
  and test_expected_reader_rejection_returns_only_its_safe_reason.
- tests/integration/provider_core/normative/test_nmrnet_reports.py::
  test_exhausted_correction_keeps_turn_reason_and_private_parser_diagnostic_through_cleanup.

## Received scientific/preparation evidence repair, 2026-10-22

Three further receiving regressions reproduced a separate gap: when scientific
result assembly or preparation-evidence admission failed, the owning exception
kept the received payload in memory, but the protected process report omitted
useful result metadata or preparation diagnostics. Repair commit bdd95d2 adds
reviewed partial projections so the operator can identify the received result
and inspect relevant preparation failures when ordinary evidence admission fails.

The scientific-result summary reports structural facts, request hash fields with
valid SHA-256 spelling, and the prepared identity's schema, byte length and hash.
It records received geometry/row counts, inspected row counts, row-shape failures
and omissions. It copies no prediction values, coordinates or provenance blobs.
Preparation summaries retain reviewed fingerprints/counts and credential-redacted
diagnostic windows, including generation, unverified model-report and earlier
interpreter failure evidence. The projection selects known fields from its owned
preparation document. Existing
geometry/atom limits bound structural inspection; the existing 64-node failure
budget bounds interpreter entries. Diagnostic windows retain at most 8192
characters after redaction, with explicit omission counts. Malformed diagnostic
graphs do not prevent the other owned causes from reaching the operator.

ResultAssemblyFailed and PreparationEvidenceFailed now say explicitly that the
full raw result or rejected preparation payload remains only in memory. The
process report carries partial metadata/diagnostics and the underlying cause.
It cannot reconstruct the complete result and grants no salvage, replay or
repeated-science authority. The regression receives a malformed worker result
once, preserves its result-admission cause and independent cleanup cause, and
proves that another execute attempt cannot repeat that scientific dispatch.
An oversized preparation diagnostic fails before scientific prediction starts.

Final post-format qualification at bdd95d2: make
test/integration/provider-core/process passed 44 tests in 27.543 seconds. Pinned
Ruff 0.15.15 lint/format passed for the three changed Python files; diff whitespace
checks passed. The earlier 42-test run was intermediate, not the final proof.
Ephemeral local logs, not tracked repair artifacts:

- /tmp/nmrnet-received-evidence.vaZga7/red-process.log
  SHA256 45332d538ae1c49685903431a1bdc123072413228d88094eb126a81c33b2d6cc
- /tmp/nmrnet-received-evidence.vaZga7/final-formatted-process.log
  SHA256 3e51ba89a5958fbfe0e86205343da15ecddf7efa5e2f3585b5888c110dc1cbbc

Only these references are recorded here; raw logs and full private trees were
not added to version control.

References fixed at bdd95d2:

- nmrnet_provider/session.py::ResultAssemblyFailed and PreparationEvidenceFailed;
  process_reports.py::_received_result_summary and failure_evidence's
  preparation_summary and exact-owner projections.
- tests/integration/provider_core/normative/test_nmrnet_reports.py::
  test_received_result_is_identified_without_retaining_numeric_output_or_repeating_science;
  test_unretained_preparation_diagnostic_has_bounded_receiving_evidence_before_prediction;
  test_received_result_projection_bounds_malformed_geometry_and_row_metadata;
  test_owned_preparation_diagnostic_variants_keep_safe_facts_and_redact_even_valid_digest_secrets;
  test_malformed_preparation_diagnostics_do_not_prevent_other_causes_from_reaching_the_operator.

These checkpoints concern contained source and receiving-report behavior. No
live external model/API calls or native scientific execution were repeated for
these repairs. They do not clear the original permissions audit, qualify a new
installed/deployed image, or replace the earlier live-run and permission evidence.

## Aggregate fixture follow-through, 2026-10-22

The aggregate provider-core integration lane exposed missing test-input grants
and three stale core fixtures after the focused repair lanes had passed. A
contained probe inspected the recovery exceptions' actual owned causes:
PublicationFailed.cause and StartFailed.cause were ApiFailure objects rejecting
the missing configured Nmr-Api-Topology marker. Their generic TLS fixtures sent
only content-type, cache-control and content-length; these were envelope failures,
not replay expiry or clock failures.

Fixture repair 2a2f7a9 reuses the existing api_tls_peer helper for the publication
and starting tests. Their original exact retained-body, one explicit resend and
refused-repeat assertions remain. The Upload fixture separately issued a grant
expiring 2026-10-19 while the receiving owner's wall clock had reached 2026-10-22.
The positive acquisition test now freezes only provider_core.uploads.datetime.now
at 2026-10-18 around acquire(). Signing, grant parsing and monotonic deadlines
keep their own clocks; the grant date, production expiry check and existing
expired-grant refusal test are unchanged. No production implementation changed.

Focused installed-core qualification selected test_publication.py,
test_starting.py and test_upload_acquisition.py: five tests passed in 0.329 seconds.
Pinned Ruff 0.15.15 lint/format passed for those three files. The owned-cause
probe was private diagnostic code, not a new maintained runner or runtime feature.
The baseline failures remain in the ephemeral local log
/tmp/nmrnet-received-evidence.vaZga7/aggregate-provider-core.log, lines 722-784.
The focused five-test output was observed in the tool transcript, without a
separate saved log.

Harness/probe repair f096e7c grants the existing inspection-probe modules and
preparation fixtures read-only to their aggregate/dedicated test lanes. The
resource helper is granted only to the aggregate integration lane. The
inspection-only capability implements the existing immutable diagnostic-retention
contract and keeps correction evidence in its private result, with malformed
argument/key canaries excluded. This adds no scientific preparation or replay
authority. Source/test references fixed at f096e7c are tools/container.sh,
tests/test_provider_core_launcher.py, tests/integration/provider_runtime/
interpreter_ambiguity.py::_InspectionOnly and run_batch, and tests/integration/
provider_core/adversarial/test_nmrnet_interpreter_ambiguity.py.

Final aggregate qualification ran 375 tests in 65.722 seconds, OK with 11 existing
native-runtime gates skipped: six native-service tests newly discoverable after
the resource grant was repaired, three scientific-lifecycle tests, one live-worker
test and one Upload-reader test. These skips do not qualify native execution.
After that run, the resource-helper grant was narrowed to aggregate-only. The
printed aggregate argv before/after narrowing was byte-equal; the aggregate was
not rerun. Final narrowed-launcher qualification passed eight tests in 0.402
seconds, and the dedicated inspection-probe lane passed nine in 0.267 seconds.
No live model or native scientific effects were rerun for these fixture repairs.

Ephemeral local receipts under /tmp/nmrnet-received-evidence.vaZga7/:

- final-aggregate-provider-core.log
  SHA256 0f343d508273449079d5b948eb75a4358dbee5d84e72bc0d7b3ecde6701e07ec
- aggregate-before-resource-narrowing.argv and
  aggregate-after-resource-narrowing.argv, identical SHA256
  233c35bca87e083eb18e88252e8975f249dd215a763557690e2039632c19865c
- final-narrowed-launcher-module.log
  SHA256 1ca3692c56ca4704f736d5f8194df439074ec18a73c08a4a182e0ae66c8b92de
- green-probe-port.log
  SHA256 45d9e14f365bfe829e33297ff37953bec7701cf8982ce9bbe09012edec82e660

These are local test/argv references, not tracked raw evidence or an installed
production-image qualification. The original permissions and deployment limits
above remain in force.