Skip to content

feat: add noirdoc ns summary <ns> for counts-only namespace inspection - #2

Merged
comppaz merged 1 commit into
mainfrom
feat/ns-summary
Apr 27, 2026
Merged

feat: add noirdoc ns summary <ns> for counts-only namespace inspection#2
comppaz merged 1 commit into
mainfrom
feat/ns-summary

Conversation

@comppaz

@comppaz comppaz commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

Closes #1.

Summary

  • New CLI subcommand noirdoc ns summary <ns> returns only counts — total_entities and per-label by_type — never the original values.
  • Safe to call from wrappers (e.g. noirdoc-claude-plugin's /noirdoc-status), CI/audit scripts, and any pipeline that captures stdout into longer-lived buffers.
  • Companion to ns show, which remains the human-facing full-mapping dump.

Output shape matches the issue spec:

{
  "namespace": "mandant-foo",
  "total_entities": 42,
  "by_type": { "PERSON": 12, "EMAIL": 7, "IBAN": 3, "LOCATION": 15, "DATE": 5 }
}

Implementation notes

  • Reuses PseudonymMapper._counters (already maintained per unique entity inside get_or_create) via a new public get_counts_summary() method — no regex parsing of placeholder keys, no reaching into private attributes from the CLI.
  • total_entities is sourced from entity_count (canonical mapping size), by_type from the counter map. In custom-label mode (PseudonymMapper(label="X")), by_type reflects the label, matching what the placeholder format actually encodes.
  • Not-found contract is identical to ns show: stderr "Namespace '<name>' does not exist." and exit code 1.
  • No changes to storage format, namespace encryption, or detector code.

Test plan

  • tests/test_mapper.py::test_counts_summary — unit test for the new mapper method, including an assertion that originals never appear in json.dumps(summary)
  • tests/test_cli.py (new file) — CliRunner covering the happy path (asserts originals don't leak into stdout) and the not-found path (asserts the exact error message + exit 1)
  • Full mapper/namespace/CLI suite (23 tests) green
  • ruff check, ruff format --check, mypy clean on touched files
  • Manual smoke: noirdoc ns summary __does_not_exist__ → stderr message + exit 1; --help lists the new command

Pre-existing failures in test_flair_recognizer.py (missing [full] extra) and two Presidio detector tests are unrelated to this change.

Follow-up (not in this PR)

After release, noirdoc-claude-plugin's /noirdoc-status should be updated to call ns summary instead of ns list, and its PreToolUse hook should allow ns summary (still blocking ns show and lookup).

`ns show` dumps the full reverse mapping (pseudonym → original) and is
unsafe to call from any context that captures stdout — wrappers, audit
pipelines, and the noirdoc-claude-plugin all currently work around this
by either blocking the call or losing useful info.

`ns summary` returns only counts:

  { "namespace": "...", "total_entities": N, "by_type": { ... } }

Implementation reuses the per-label counter the mapper already maintains;
no regex parsing of placeholder keys, no access to private attributes
from the CLI. Not-found contract (stderr + exit 1) matches `ns show`.

Closes #1
@comppaz
comppaz merged commit 4950595 into main Apr 27, 2026
3 checks passed
@comppaz
comppaz deleted the feat/ns-summary branch April 27, 2026 08:48
comppaz added a commit that referenced this pull request Apr 27, 2026
The v0.1.1 tag shipped without a corresponding changelog section, so the
daemon (PR #3) was undocumented and `ns summary` (PR #2) was still parked
under [Unreleased]. Backfill the section now so the GitHub release link
(which dereferences to CHANGELOG.md) and future readers see what 0.1.1
actually contained. Documentation-only; no code change, no re-tag.
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.

Add noirdoc ns summary <ns> — counts-only namespace inspection

1 participant