Repository navigation
feat(graph): add typed workflow execution and evidence qualification - #302
Closed
binaryaaron wants to merge 34 commits into
Closed
binaryaaron wants to merge 34 commits into
binaryaaron wants to merge 34 commits into
Conversation
9 of 14 tasks
Collaborator
Author
|
/nvskills-ci |
Add the engine-side graph values and workflow modules (identity and reference values, workflow declarations, static and dynamic admission and substitution, composition and the metered compiler budget) together with the closed effect and artifact-shape values used by later layers. Introduce the lazy public anonymizer.graph facade over them. Tests cover static workflow analysis and the compiler reference, with the workflow_static corpus. Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com> Co-Authored-By: Claude <noreply@anthropic.com>
Add the engine-side activation modules (activation values, topology and reducer), data-graph declarations and validation, canonical records, capability declarations and bounded plan preparation. Tests and references cover activation, data graphs and the compiler. Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com> Co-Authored-By: Claude <noreply@anthropic.com>
Add request policies, values and receipts with a pure reducer, typed context and its admission, resource leases and cleanup facts, ingress envelopes and bounded content-free observations. Add the detection and Rewrite artifact types that requests carry. Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com> Co-Authored-By: Claude <noreply@anthropic.com>
…nsport Add execution declarations and sealed results, bounded blocking-worker adapters, a single physical request driver, callback-ingress inspection, foreign transport entry with a client lease, and asynchronous initial context binding. Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com> Co-Authored-By: Claude <noreply@anthropic.com>
Add execution admission, the invocation runtime and scheduling, dispatch, delegated slot borrowing, frames, map and context materialization, publication and provenance, cleanup, entry points and the executor, plus the NDD source frame. Tests cover effects, map, delegated, foreign and optional-tail conformance with their references. Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com> Co-Authored-By: Claude <noreply@anthropic.com>
Add evidence admission and authentication, provenance reconciliation and release qualification, with the qualification and evidence suites, witnesses and the evidence model. Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com> Co-Authored-By: Claude <noreply@anthropic.com>
… SDK Add request inspection and extensions (context providers and retained-result views) and lazy root-package exports including graph. Document the public graph SDK in docs/concepts/graph-sdk.md with mkdocs navigation, reference pages and a provider-free example, and add the public API and export-surface tests. Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com> Co-Authored-By: Claude <noreply@anthropic.com>
NddAdapter.run_workflow gains optional source_frame, request_bridge and rewrite_binding parameters; the change is additive apart from removing the private _detect_missing_records. Add the version-qualified DataDesigner request entry, row partitioning and source positions, stage binding, the Rewrite evaluation binding, the data-designer==0.9.4 pin with a drift test, and the compat pytest marker. Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com> Co-Authored-By: Claude <noreply@anthropic.com>
Add test_production_contracts.py, a provider-free compatibility oracle for the public facade covering Redact projection and failure, saved-result evaluation and DataDesigner retry. It lands before any route moves so each cutover is measured against it. Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com> Co-Authored-By: Claude <noreply@anthropic.com>
Admitted core, optional-latent and final stages replace the builtin detection controller. Add the whole-frame detection and Redact consumers, the shared harness (_opaque_redact, _frame_publication, harness retention), the NDD route module _route.py and the graph SDK _authoring_defaults.py. Redact evidence checking rejects empty templates, with matching config, replace.md and skill updates and the skill signature files. Validation-plugin and local-transform mediation and the frozen detection corpora are included. This commit also carries the logging hunks of replace/replace_runner.py. Part of the B10–B12 route cutover; the full suite is green again at B12. Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com> Co-Authored-By: Claude <noreply@anthropic.com>
…acade Graph control owns Rewrite transitions for both DataDesigner schedules. The legacy repair loop and CombinedRewriteWorkflow.run are retired, and one source-bound invocation runs detection plus the semantic tail. The public Anonymizer facade is routed here, including the logging hunks of interface/anonymizer.py. Evaluation source-position fixes are included; evaluate() keeps its existing path. Part of the B10–B12 route cutover; the full suite is green again at B12. Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com> Co-Authored-By: Claude <noreply@anthropic.com>
Move Substitute map selection, generation and acceptance under graph control, with native map requests, compatibility entries and the Substitute lineage and compat suites. This closes the route cutover; the full suite is green from here. Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com> Co-Authored-By: Claude <noreply@anthropic.com>
Keep sensitive payloads out of library log output. This covers the logging change except interface/anonymizer.py and replace/replace_runner.py, whose logging hunks ride B11 and B10. Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com> Co-Authored-By: Claude <noreply@anthropic.com>
Add docs/development/graph-sdk-cutover.md and the AGENTS.md section describing the graph SDK preview branch rules. Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com> Co-Authored-By: Claude <noreply@anthropic.com>
Add tools/dogfood/ with a README, compare.py, dogfood_run.py and model and provider configs for comparing this branch against the released package. Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com> Co-Authored-By: Claude <noreply@anthropic.com>
binaryaaron
force-pushed
the
codex/anonymizer-graph-sdk-contracts
branch
from
October 21, 2026 01:22
2fc6d81 to
4bded5e
Compare
Replace the lazy attribute table with static imports and a sorted __all__ that binds the same names to the same objects. This drops the import_module/TYPE_CHECKING mirror of the export list. The pure-import test no longer asserts that importing anonymizer.graph avoids pandas; it keeps its two engine-component cases. The export pin is re-recorded for the new sorted __all__ order. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Importing anonymizer.graph now pulls in the engine eagerly. Defer the four edges that dragged in pandas and numpy: the harness frame types become TYPE_CHECKING imports with local imports at their few runtime uses, and rewrite artifacts import numpy and pandas inside the one method that needs them. import anonymizer.graph drops from roughly 580 ms and 735 modules to roughly 290 ms and 280 modules, with pandas no longer loaded. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
…equest bridge Restore the upper-bounded DataDesigner range used on main instead of the exact 0.9.4 pin. The graph request bridge no longer compares the installed version; it checks the private DataDesigner hooks it relies on: - at bind time, before any work runs: DataDesigner._create_resource_provider, ModelRegistry's model_facade_factory parameter and ModelFacade.agenerate; - when DataDesigner first creates a provider or facade, before any request: the registry's facade factory and the facade client's HTTP fields, which are instance attributes and cannot be checked earlier. A missing hook raises AnonymizerWorkflowError naming the attribute, the supported range and the installed version. The bridge records the failure and re-raises it when the binding exits, so DataDesigner's per-row error handling cannot turn it into dropped records. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
…oks lazily data-designer 0.9.5 classifies httpx.NetworkError and RemoteProtocolError (for example a ReadError) as connection errors, so its request executor now retries them. A bridge that admits one physical attempt per chain (detection) then saw a second attempt and rejected the whole invocation, where 0.9.4 kept the record's outcome unknown. For single-attempt chains the bridge now hands DataDesigner those errors as a SingleAttemptTransportError, which every supported release classifies as a non-retryable API error; errors 0.9.4 already retried (ConnectError, timeouts) are passed through unchanged. Private DataDesigner names are no longer imported at module scope, so importing anonymizer does not depend on them: - create_retry_transport and ParserException are resolved lazily and checked when the bridge binds; - the health-check skip switch and AsyncTaskScheduler's salvage_max_rounds, used only by the Substitute native map, are checked when the map plans its requests, before any work runs; - ensure_async_engine_loop is imported on first use. Each missing hook raises the standard capability error. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Every route runs DataDesigner through NddAdapter.run_workflow, which binds the source frame to DataDesigner's private dataset builder. A release without those hooks failed with a bare AttributeError message. The binding now checks, before any work runs, DataDesigner._create_dataset_builder and the artifact-storage module's BatchStage members and SDG_CONFIG_FILENAME. When DataDesigner creates the builder, before it runs, it checks the builder's _initialize_generators_and_graph, _write_builder_config and _data_designer_config, and the storage methods and paths it wraps. Each failure raises the standard capability error naming the attribute, the supported range and the installed version. A real DataDesigner always requires the hooks; a caller's stand-in designer without a dataset builder is still left unbound. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Builtin Redact, Annotate and Hash, and builtin detection or Substitute map generation reached from a caller override through super(), ran their DataDesigner calls on a library worker thread. In 0.4.0 they ran on the thread that called run() or preview(). Hand those bodies to the caller's thread like every other body, and run a handoff issued on the serving thread inline instead of raising. New placement tests pin 0.4.0 behaviour for builtin Redact, Annotate and Hash, for detectors that delegate to the builtin run(), and for Substitute under a caller replace runner, from the main thread, a non-main thread and inside a running event loop. The route-resolution rows keep pinning which route each runner shape takes and now pin that every route hands its body to the caller. The interrupt-drain test delivers a real SIGINT instead of simulating one in the kernel's completion wait, which the caller no longer reaches while a body runs. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
…r pool Every synchronous body already returned to the caller's thread, but the kernel still started a one-worker pool per invocation whose thread only forwarded the body back to the caller, and the caller polled its queue every 10 ms. Submit delegated bodies straight to the caller's queue through a caller-thread submitter, wake the caller with a completion marker instead of the poll, and drop the per-invocation pool and the caller_callbacks switch, which every entry now sets. Standalone use outside a facade invocation keeps the worker submitter and BlockingPool. A Ctrl-C that lands after a body's result was set no longer turns into an InvalidStateError. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
The patch replaced DataDesigner's scheduler wait process-wide so that a graph cancellation reached a DataDesigner run waiting on a library worker thread. Every DataDesigner wait now runs on the thread that called the public entry point, where Ctrl-C reaches DataDesigner's own handler as in 0.4.0, so the patch is no longer needed. Extend the subprocess Ctrl-C test to builtin Redact, Redact under a caller detector that delegates to the builtin run(), and Substitute under such a detector. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
run(), preview() and evaluate() run every synchronous body, builtin or supplied, on the thread that called them, at every depth, with a copy of the caller's context variables. Say so in the graph SDK concepts page and the cutover notes, correct the claim that callbacks get the caller's context rather than a copy, and state where a builtin reached through super() runs. Builtin detection now always receives the caller handoff, so its inline fallback is gone. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
A Ctrl-C that landed after the caller took a body from its queue, or just before it settled the body's future, left that future unresolved. The host then waited for it forever and the drain loop absorbed every further Ctrl-C, so the process only ended on SIGKILL. Track every queued body until it settles and, when an interrupt leaves serving, settle any that remain as failed before re-raising. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Caller code and every DataDesigner wait run on the caller's thread, but the per-invocation event-loop thread still runs internal bookkeeping and DataDesigner's engine threads still run Anonymizer column generators, as on main. Say so instead of claiming the loop thread runs no Anonymizer code, and fix a comment that still said a nested handoff raises. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
When a second Ctrl-C landed while the drain loop was serving, the interrupt handler asked the host loop to cancel even after that loop had closed, and the resulting RuntimeError replaced the KeyboardInterrupt. Share one guarded stop request between the handler and the drain loop. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
A second Ctrl-C landing inside the interrupt handler, before it settled the waiting bodies, could still leave one unsettled and the drain loop waiting forever. Settle first, then request the stop, and settle again on every drain pass so no interrupt window skips it. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
After an interrupt settles every waiting body, the drain loop could still take one of them from the queue and set its result again, which raised InvalidStateError in place of the KeyboardInterrupt. Skip bodies that are already settled, and test the case directly. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Until the SDK is published, anonymizer.graph and the engine modules behind it may change names, export order, signatures, defaults, exception constructors, pickles and import cost. The tests that pin them are refactor safety nets, re-recorded with the change they cover. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Settled bodies resolve as failures rather than raising, so the test's operation can finish before the stop request reaches the host. The interrupt path then reads the result's execution, which the bare list the operation returned does not have, and the AttributeError replaced the KeyboardInterrupt. Return a result shaped like every production operation's. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Brings in the quality and throughput tuning guide (#261). The only conflict was the mkdocs nav; both entries are kept: Graph SDK under Concepts, and the tuning guide at the top level, as on main. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Collaborator
Author
|
/nvskills-ci |
binaryaaron
requested review from
a team,
afourniernv,
andreatnvidia,
lipikaramaswamy and
memadi-nv
October 21, 2026 14:57
Signed-off-by: nvskills-svc-account <svc-nvskills-signing@nvidia.com>
…#318) dataclasses.replace() now raises TypeError instead of ValueError for a missing InitVar, so test_copies_require_the_owner_key accepts either type while still asserting the message. The pinned export facts recorded the enum-class signature, which newer 3.12 and 3.13 patch releases report as (*values); enum classes now record no signature, as exception classes already do, and the three recorded entries were updated to match. 🤖 Generated with Claude Code Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com> Co-authored-by: Claude <noreply@anthropic.com>
Collaborator
Author
|
This PR was closed automatically when its branch was renamed to |
binaryaaron
added a commit
that referenced
this pull request
Oct 21, 2026
The line branch was renamed from codex/anonymizer-graph-sdk-contracts to aagonzales/graph-sdk/feat/main, which closed PR #302; draft PR #319 now carries the branch. AGENTS.md names the new branch and both files link PR #319, noting that it was formerly #302. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
this is comically large and the result of a few attempts to do a heavy, semi-autonomous agent run. i will be making changes to remove larges swaths of code and weird tests from the repo, bc the initial +130k loc is absurd on its face.
Summary
This PR moves Anonymizer's production pipelines (Rewrite, detection, Substitute) from hand-written per-route controllers onto a typed Graph SDK, behind the unchanged
AnonymizerAPI: the public DataFrame behavior is preserved under REQ 1 except the accepted deltas listed in the status block. DataDesigner execution stays behindNddAdapter.run_workflow().anonymizer.graphis not a compatibility contract yet. Until the Graph SDK is published, its names,__all__order, signatures, defaults, exception constructors, class pickles and import cost may change in any commit. Tests that pin them are refactor safety nets and are re-recorded with the change. The contract is theAnonymizerAPI and config of 0.4.0.This branch (
aagonzales/graph-sdk/feat/main) is the long-lived base of the Graph SDK feature line, not a merge candidate for now. Later work, including PR2, builds on it and lands here as PRs.Done: Rewrite, detection and Substitute run graph-owned end to end, with their legacy controllers deleted; a scoped logging correction keeps record content out of library diagnostics. The history is squashed into 15 reviewable commits; #314–#316, a main merge and #318 followed. Evaluation, native admission and Session are PR2+.
For dogfooders and reviewers
This branch moves the production pipelines onto the Graph SDK while preserving the public DataFrame
API. Its history was rewritten once, on 2026-10-20, into 15 commits with the same tree as
2fc6d810; otherwise itonly fast-forwards. Test at the latest commit and state the SHA you ran in every comment (current pin:
e0d8b317).Setup (in this order, details in
tools/dogfood/README.md):uv sync --frozen --extra notebooks; start the detector server(
uv run python tools/serve_gliner.py --host 127.0.0.1 --port 8001— no bearer token is needed unless you setANONYMIZER_LOCAL_GLINER2_TOKENwhen starting it); export the provider key named intools/dogfood/providers.yaml(NVIDIA_INFERENCE_API_KEY; or edit the file for your provider). Smoke test:pytest -m compat(~1 min), thenpython examples/graph_sdk/local_workflows.py(provider-free).Dogfood kit:
tools/dogfood/dogfood_run.pyruns one route in one environment and writes a comparableresult bundle;
tools/dogfood/compare.pydiffs two bundles. Run the same route against the released wheel ina second environment at matching versions (
pandas==2.3.3,data-designer==0.9.4) and diff; against apandas 3 install the only expected differences are the trace-column dtype rows listed below.
How to approach it, in this order. No line-by-line review yet; the branch is being cut down substantially.
on your end: detection+Redact, Substitute, Rewrite via
runandpreview, diffed against the released 0.4.0with
tools/dogfood/. Highest-value surfaces: Substitute and Rewrite (replacement maps), customdetectors/runners, nullable or non-string columns, Ctrl-C mid-run. A one-line "clean at , pool "
comment is as useful as a diff.
release baseline; post the deltas (instructions in the team channel).
a case like integrating with a partner project — and tell us where the semantics or composability surprised
you, where
docs/concepts/graph-sdk.mdand the behaviour disagree, and what you could not express. Tag[sdk-semantics]; those are not parked.What to look at:
result.failed_records;trace_dataframe["_replacement_application"]— a non-zeroskipped_span_countmeans original text survived; a null*_rewrittenwithneeds_human_review=Trueis arewrite WITHHELD by design, not a crash; output column dtypes vs the release;
leakage_massandneeds_human_reviewon Rewrite; the console log at DEBUG for any entity value. Always state the model pooland provider you used — results differ by model. Rewrite with
nemotron-3-superfails structured outputs onboth the branch and 0.4.0; use the default pool for Rewrite comparisons.
What matters now is correctness and discrepancies with main / the released package: wrong outputs,
crashes, dtype/NaN/row-handling defects, PII or exception content leaking into logs/traces. Architecture,
naming, duplication, size and style comments are not useful yet — an active minimization effort owns them
and they will be parked (not ignored) — see the triage replies in the footer.
File findings as comments on this PR — one finding per comment, tagged
[breaks-compat],[wrong-output],[crash],[privacy],[docs-gap], or[sdk-semantics](phase 3), with: the exact SHA you reviewedagainst, the topic area (route/surface), smallest repro (provider-free if possible), and expected vs actual
(one line each).
All coordination for this branch happens on this PR; there is no separate guide or issue form.
Status, known-open, and accepted behavior deltas
Branch role (maintainer, 2026-10-21): this branch is the long-lived base of the graph-SDK feature line. It is not
scheduled to merge into
main; later work, including PR2, lands here as reviewed PRs, andmainis merged in as itsPRs land. Dogfood it as a moving base: the pin in the dogfooder block is the current head, and the known-open and
accepted-delta lists below describe that head.
Live validation (2026-10-19, operator dogfood vs released 0.4.0 at
5473e8ef; first run 2026-10-16 at0842f5c5reported the same outcome): detection+Redact, Substitute and Rewrite run end to end on two liveprovider pools via
runandpreview; outputs match the release on columns, dtypes (under aligneddependencies; pandas 3 differences are the accepted deltas below), entity coverage, replacement-text leakage
and log hygiene. Timing within 0.7–1.5× of the release across routes; the Substitute replacement-map
serialization fixed at
e309c617holds (10 requests in flight). Evidence retained in the campaign's records.Size (maintainer decision, 2026-10-21): the original targets were +10K, then +5K, non-test Python lines over the
0.4.0 baseline
30b6d82a. Measured at pin188ef369: +32,760 non-test (+31,642 excludingtools/) and+57,383 test. The targets were revised rather than met because the branch was reduced in stages on top of the
reviewed implementation; a rebuild was ruled out. Continuing reduction and simplification will be done in commits
directly to this branch or in PRs made to it directly (the first three, caller-thread execution for every synchronous
body, an eager
anonymizer.graphfacade and a DataDesigner version range, have landed), on branches named<author>/graph-sdk-<name>. Size, naming and layering comments stay parked until that work lands (see triage replies).Known-open — don't file these:
deferred to PR2+ (maintainer scope ruling, 2026-10-16).
evaluate()ships on its existinglegacy path — behavior-preserving; don't file "evaluation isn't graph-owned" findings.
restructured. Internal modules, names, and layering will churn heavily — architecture/naming
feedback stays parked (see triage replies).
internal ~2.1× measurement came from a quadratic scan in the final-output assembly, fixed in
0cc24a4a).About 7–8 ms/row of CPU orchestration remains on top of model time. Don't file timing findings under
1.1× of the release; do file anything above it with row count and model pool.
anonymizer.graphSDK surface is not a contract in this PR: its names, export order, signatures,defaults, exception constructors, pickles and import cost may change until the SDK is published under the
RFC's publication gate (REQ 13). Tests that pin them are refactor safety nets, re-recorded with the change
that moves them. Continuity, adaptive retrieval, decision waits, state revisions and absence queries have
moved to PR2+. A changed or removed graph export is not a finding; the shipped
Anonymizer/config API andthe documented result columns are the stable target.
OSError: [Errno 98] Address already in usefromDataDesigner's metrics server, then "OpenTelemetry metrics are unavailable; continuing without them."
Harmless.
its map; the trace's
skipped_span_countshows it. Pre-existing in 0.4.0, model-dependent (seen withnemotron-3-super, not with the default pool). Tracked for PR2; still report it with your model pool so
we see the frequency.
Accepted behavior deltas (a released-vs-branch diff covered by a row here is not a finding):
_needs_repair/_rewrite_replacement_readycolumns arebool(release:object, NaN on no-entity rows); on the staged path_needs_repairisFalsefor withheld rows (releaseTrue), since the withheld text is not repairedtrace_dataframeonly8f5a9b74,d34ccdfbformat_template(e.g.""or"{label:.0}") raises a configuration error, and a label template that renders empty during replacement raises instead of silently keeping the original entity text (0.4.0 accepted these and could leave the entity in place). Rationale: fail-closed — an empty template would publish the original PII. Migration: supply a non-empty template (default[REDACTED_{label}])0c1b719a_privacy_qa_reanswer,_quality_qa_reanswer,_quality_qa_compare) hold empty structures instead of NaN on rows with no entities; a batch where no row has entities adds these 4 trace columns (release: absent)trace_dataframeonly (both schedules, run/preview, evaluate)b2c9c7bfevaluate()on a Rewrite preview returns the trace_anonymizer_record_idcolumn asstrdtype instead ofobjectevaluate,trace_dataframeonlyb2c9c7bfnum_recordssmaller than the returned entity rows: the branch returns the requested n rows and drops the extra row (failed_recordsempty); 0.4.0 and main crash with a raw pandasValueErrorin_join_new_columnspreview(Redact/Substitute preview behave the same on both)b2c9c7bfevaluate()on a Substitute/Redact result whose caller-supplied detector duplicated rows returns one row per result row (7 in the duplicated-detector case); 0.4.0 and main return 9 because their replace-judge merge multiplies the duplicated rowsevaluateafter Replace with caller-supplied detectors3c7c7cccevaluate()andresult.rewrite_configuse the privacy goal as admitted (0.4.0 used the goal object as mutated by the detection stage)evaluatea67ef6bdEffectRejected, surfaced as a failed record) instead of 0.4.0's silent projection of the first evaluation state; unreachable through built-in routes, only via callerrun_workflowoverrides or hand-built rowsrun_workflowoverrides1301c619build_graph, adapterrun_workflowoverrides) are not visible to the caller afterrun/preview/evaluatereturn; values set before the call are visible inside (0.4.0 ran caller code in the caller's live context, so writes leaked out). Rationale: every public entry runs in a copy of the caller's context, copy-in and no copy-out, the only semantics an async entry can also offer. Migration: pass results back through return values or your own objects, not through context variables2fc6d810What has landed
The 15 commits (history squashed 2026-10-20; tree unchanged)
a75b1deeanonymizer.graphfacade404f64fa6c14a4fa729a577c849a203ad684c273bceffa9d3de54364e624f10d0b51cfefced493321fdb2937372bbd0b60959fa74bded5e6Current numbers
30b6d82a*.py, at188ef369)3a208200(pandas 2 and 3); parity corpus vs 0.4.0: 0 blocking188ef3692fc6d810: one identical wheel on Python 3.11–3.13;compat265 from the installed wheelRemaining work
<author>/graph-sdk/<type>/<name>, the naming order proposed in docs: allow topic prefixes in branch names for long-lived feature lines #312). Landed: refactor(graph): make anonymizer.graph an eager facade #314 (eageranonymizer.graphfacade), build: accept data-designer >=0.9.4,<0.10 with capability-checked hooks #315 (DataDesigner>=0.9.4,<0.10), fix(graph): run every Anonymizer body on the caller's thread #316 (caller code and builtin DataDesigner waits on the caller's thread), test(graph): accept CPython patch-release differences in graph SDK tests #318 (tests pass on every supported Python 3.13 patch release).188ef369). Later main PRs come in the same way as they land, with a port PR when they touch graph-owned code.Verification
Each PR into this branch gets the full suite (pandas 2 and 3), repository checks and independent review.
Related Issue and Plan
Maintainer-directed Graph SDK implementation; no linked issue required. See the public SDK guide, cutover inventory and provider-free example.
Type of Change
Contributor Checklist
Triage replies (paste verbatim)
Parked:
Needs repro:
Model-dependent: