Skip to content

Commit 5613880

Browse files
rustyconoverclaude
andcommitted
metadata: full vgi-lint conformance at latest linter; bump deps; add browsable table
Bring vgi-pii to a clean vgi-lint gate (score 64 -> 95, 0 findings at fail-on: info) against the LATEST vgi-lint-check, and drop the pinned `version: "0.37.0"` from the CI action so the fleet tracks latest. Metadata fixes: - Fully qualify every example query and agent-test reference_sql as `pii.main.<object>` (was `pii.<object>`); under-qualified refs silently failed coverage attribution and --execute. Fixes VGI511/VGI520 across all six objects (example_coverage 0.0 -> 1.0, test_coverage 0.0 -> 1.0). - Migrate the retired `vgi.result_columns_md` tag (VGI414) to the structured `vgi.result_columns_schema` JSON on both table functions. - Remove complete runnable SELECT ... FROM queries from vgi.doc_md (VGI179) on has_pii / detect_pii / supported_entities; replace with signature + column prose. Examples live in vgi.example_queries. - Rewrite the two bare `SELECT *` examples into projected/filtered analytical queries (VGI514). - Add a browsable `entity_types` discovery table (VALUES-style, backed by the existing supported_entities generator) so the worker is not table-functions- only (VGI146), with its own docs, category, example queries, and a recognizes-credit-card agent task. Dependencies: - Bump vgi-python 0.9 -> 0.14 (pinned <0.15) and vgi-rpc 0.22 -> 0.24; commit the refreshed uv.lock. vgi-python 0.15 changes the table RPC schema (required_filters: list<list<string>>) which the currently released signed vgi extension does not yet accept, so a worker exposing a table cannot attach at 0.15; 0.14 matches the conformant sibling vgi-conform and is green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 1d2d557 commit 5613880

6 files changed

Lines changed: 235 additions & 89 deletions

File tree

.github/workflows/ci.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ jobs:
102102
- name: vgi-lint
103103
uses: Query-farm/vgi-lint-check@v1
104104
with:
105-
version: "0.37.0"
106105
location: "uv run --python 3.13 ${{ github.workspace }}/pii_worker.py"
107106
fail-on: info
108107

pii_worker.py

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# /// script
22
# requires-python = ">=3.13"
33
# dependencies = [
4-
# "vgi-python[http]>=0.9.0",
4+
# "vgi-python[http]>=0.14.0,<0.15.0",
55
# "presidio-analyzer>=2.2",
66
# "presidio-anonymizer>=2.2",
77
# "spacy>=3.7",
@@ -25,12 +25,12 @@
2525
INSTALL vgi FROM community; LOAD vgi;
2626
ATTACH 'pii' (TYPE vgi, LOCATION 'uv run pii_worker.py');
2727
28-
SELECT pii.has_pii('Call John Smith at john@example.com'); -- true
29-
SELECT pii.redact('Call John Smith at john@example.com'); -- 'Call <PERSON> at <EMAIL_ADDRESS>'
30-
SELECT pii.anonymize('Call John Smith at john@example.com'); -- 'Call **** at ****************'
31-
SELECT pii.pii_types('Call John Smith at john@example.com'); -- ['EMAIL_ADDRESS', 'PERSON']
32-
SELECT * FROM pii.detect_pii('Call John Smith at john@example.com');
33-
SELECT * FROM pii.supported_entities() ORDER BY entity_type;
28+
SELECT pii.main.has_pii('Call John Smith at john@example.com'); -- true
29+
SELECT pii.main.redact('Call John Smith at john@example.com'); -- 'Call <PERSON> at <EMAIL_ADDRESS>'
30+
SELECT pii.main.anonymize('Call John Smith at john@example.com'); -- 'Call **** at ****************'
31+
SELECT pii.main.pii_types('Call John Smith at john@example.com'); -- ['EMAIL_ADDRESS', 'PERSON']
32+
SELECT * FROM pii.main.detect_pii('Call John Smith at john@example.com');
33+
SELECT * FROM pii.main.supported_entities() ORDER BY entity_type;
3434
"""
3535

3636
from __future__ import annotations
@@ -43,7 +43,7 @@
4343

4444
from vgi_pii import engine
4545
from vgi_pii.scalars import SCALAR_FUNCTIONS
46-
from vgi_pii.tables import TABLE_FUNCTIONS
46+
from vgi_pii.tables import DISCOVERY_TABLES, TABLE_FUNCTIONS
4747

4848
_CATALOG_DESCRIPTION_LLM = (
4949
"Detect and redact personally-identifiable information (PII) in free text directly in SQL, "
@@ -86,7 +86,7 @@
8686
"redaction powers safe sharing, export, and archival. Every operation accepts an optional "
8787
"ISO language argument (defaulting to English) and treats NULL or blank input gracefully.\n\n"
8888
"```sql\n"
89-
"SELECT pii.redact('Call John Smith at john@example.com');\n"
89+
"SELECT pii.main.redact('Call John Smith at john@example.com');\n"
9090
"-- 'Call <PERSON> at <EMAIL_ADDRESS>'\n"
9191
"```\n\n"
9292
"Learn more from the [Presidio documentation](https://microsoft.github.io/presidio/), the "
@@ -218,7 +218,7 @@
218218
"Does the text 'Contact Jane Doe at jane@example.com' contain any "
219219
"personally-identifiable information? Return a single boolean value."
220220
),
221-
"reference_sql": "SELECT pii.has_pii('Contact Jane Doe at jane@example.com')",
221+
"reference_sql": "SELECT pii.main.has_pii('Contact Jane Doe at jane@example.com')",
222222
"success_criteria": (
223223
"Returns a single boolean value that is true, obtained by calling the worker's "
224224
"PII-presence predicate on the given text."
@@ -228,7 +228,7 @@
228228
{
229229
"name": "list-pii-types",
230230
"prompt": ("List the distinct PII entity types present in the text 'Contact Jane Doe at jane@example.com'."),
231-
"reference_sql": "SELECT pii.pii_types('Contact Jane Doe at jane@example.com')",
231+
"reference_sql": "SELECT pii.main.pii_types('Contact Jane Doe at jane@example.com')",
232232
"success_criteria": (
233233
"Returns the sorted array of distinct PII entity types (such as EMAIL_ADDRESS and "
234234
"PERSON) present in the text."
@@ -241,7 +241,7 @@
241241
"Produce a copy of the text 'Email jane@example.com now' in which every PII value "
242242
"is replaced by a tag naming its entity type (for example <EMAIL_ADDRESS>)."
243243
),
244-
"reference_sql": "SELECT pii.redact('Email jane@example.com now')",
244+
"reference_sql": "SELECT pii.main.redact('Email jane@example.com now')",
245245
"success_criteria": (
246246
"Returns the input text with each detected PII entity replaced by a <TYPE> tag naming its entity type."
247247
),
@@ -253,7 +253,7 @@
253253
"Produce a copy of the text 'Email jane@example.com now' in which every PII value's "
254254
"characters are masked with asterisks."
255255
),
256-
"reference_sql": "SELECT pii.anonymize('Email jane@example.com now')",
256+
"reference_sql": "SELECT pii.main.anonymize('Email jane@example.com now')",
257257
"success_criteria": (
258258
"Returns the input text with each detected PII entity's characters overwritten by '*' asterisks."
259259
),
@@ -267,7 +267,7 @@
267267
),
268268
"reference_sql": (
269269
"SELECT entity_type, text FROM "
270-
"pii.detect_pii('Contact Jane Doe at jane@example.com') ORDER BY entity_type, text"
270+
"pii.main.detect_pii('Contact Jane Doe at jane@example.com') ORDER BY entity_type, text"
271271
),
272272
"success_criteria": (
273273
"Returns one row per detected PII entity, each showing the entity type and the "
@@ -279,13 +279,26 @@
279279
{
280280
"name": "count-supported-entity-types",
281281
"prompt": "How many distinct PII entity types can this worker's analyzer detect?",
282-
"reference_sql": "SELECT count(*) FROM pii.supported_entities()",
282+
"reference_sql": "SELECT count(*) FROM pii.main.supported_entities()",
283283
"success_criteria": (
284284
"Returns the number of distinct PII entity types the analyzer supports, obtained "
285285
"from the worker's supported-entities discovery function."
286286
),
287287
"ignore_column_names": True,
288288
},
289+
{
290+
"name": "recognizes-credit-card",
291+
"prompt": (
292+
"Does this worker's list of recognizable PII entity types include credit-card "
293+
"numbers (the CREDIT_CARD type)? Return a single boolean value."
294+
),
295+
"reference_sql": ("SELECT count(*) > 0 FROM pii.main.entity_types WHERE entity_type = 'CREDIT_CARD'"),
296+
"success_criteria": (
297+
"Returns a single boolean that is true, determined by looking up CREDIT_CARD in the "
298+
"worker's browsable table of recognizable entity types."
299+
),
300+
"ignore_column_names": True,
301+
},
289302
]
290303

291304
_CATALOG_TAGS = {
@@ -324,6 +337,7 @@
324337
"topic": "pii-detection-and-redaction",
325338
},
326339
functions=[*SCALAR_FUNCTIONS, *TABLE_FUNCTIONS],
340+
tables=list(DISCOVERY_TABLES),
327341
),
328342
],
329343
)

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ classifiers = [
1818
"Typing :: Typed",
1919
]
2020
dependencies = [
21-
"vgi-python>=0.9.0",
21+
"vgi-python>=0.14.0,<0.15.0",
2222
"presidio-analyzer>=2.2",
2323
"presidio-anonymizer>=2.2",
2424
"spacy>=3.7",
@@ -30,7 +30,7 @@ dependencies = [
3030
# addition to stdio. That path needs vgi-python's `http` extra (waitress).
3131
# CI's http transport leg installs this via `uv sync --extra http`.
3232
http = [
33-
"vgi-python[http]>=0.9.0",
33+
"vgi-python[http]>=0.14.0,<0.15.0",
3434
]
3535
dev = [
3636
"pytest>=8",

uv.lock

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vgi_pii/scalars.py

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,16 @@
6161
),
6262
doc_md=(
6363
"# has_pii\n\n"
64-
"A scalar predicate that answers a single question: *does this text contain PII?*\n\n"
65-
"## Usage\n\n"
66-
"```sql\n"
67-
"SELECT pii.has_pii('Call John Smith at john@example.com'); -- true\n"
68-
"SELECT id FROM messages WHERE pii.has_pii(body); -- rows needing scrubbing\n"
69-
"```\n\n"
70-
"## Notes\n\n"
71-
"Pass an explicit language as the second argument (`has_pii(text, 'en')`) to scan "
72-
"non-English text. NULL or blank input yields NULL rather than `false`."
64+
"A scalar predicate that answers a single question: *does this text contain PII?* "
65+
"Call it inline in a projection to tag rows, or in a `WHERE` clause to keep only "
66+
"the rows that need privacy handling before they are shared, exported, or archived.\n\n"
67+
"## Behaviour\n\n"
68+
"- Returns `true` as soon as any entity (a person name, email, phone number, credit "
69+
"card, US SSN, location, URL, IP address, ...) is detected, otherwise `false`.\n"
70+
"- Pass an explicit ISO language as the optional second argument "
71+
"(`has_pii(text, 'en')`) to scan non-English text.\n"
72+
"- `NULL`, empty, or whitespace-only input yields `NULL` rather than `false`.\n\n"
73+
"See this function's example queries for a runnable demonstration."
7374
),
7475
keywords=[
7576
"pii",
@@ -109,7 +110,7 @@
109110
"surrounding text intact.\n\n"
110111
"## Usage\n\n"
111112
"```sql\n"
112-
"SELECT pii.redact('Call John Smith at john@example.com');\n"
113+
"SELECT pii.main.redact('Call John Smith at john@example.com');\n"
113114
"-- 'Call <PERSON> at <EMAIL_ADDRESS>'\n"
114115
"```\n\n"
115116
"## Notes\n\n"
@@ -156,7 +157,7 @@
156157
"the rest of the text readable.\n\n"
157158
"## Usage\n\n"
158159
"```sql\n"
159-
"SELECT pii.anonymize('Call John Smith at john@example.com');\n"
160+
"SELECT pii.main.anonymize('Call John Smith at john@example.com');\n"
160161
"-- 'Call **** at ****************'\n"
161162
"```\n\n"
162163
"## Notes\n\n"
@@ -202,7 +203,7 @@
202203
"`VARCHAR[]`.\n\n"
203204
"## Usage\n\n"
204205
"```sql\n"
205-
"SELECT pii.pii_types('Call John Smith at john@example.com');\n"
206+
"SELECT pii.main.pii_types('Call John Smith at john@example.com');\n"
206207
"-- ['EMAIL_ADDRESS', 'PERSON']\n"
207208
"```\n\n"
208209
"## Notes\n\n"
@@ -263,7 +264,7 @@ class Meta:
263264
tags = _HAS_PII_TAGS
264265
examples = [
265266
FunctionExample(
266-
sql="SELECT pii.has_pii('Call John Smith at john@example.com')",
267+
sql="SELECT pii.main.has_pii('Call John Smith at john@example.com')",
267268
description="Detect whether text contains PII",
268269
),
269270
]
@@ -288,7 +289,7 @@ class Meta:
288289
tags = _HAS_PII_TAGS
289290
examples = [
290291
FunctionExample(
291-
sql="SELECT pii.has_pii('Call John Smith at john@example.com', 'en')",
292+
sql="SELECT pii.main.has_pii('Call John Smith at john@example.com', 'en')",
292293
description="Detect PII with an explicit language",
293294
),
294295
]
@@ -320,7 +321,7 @@ class Meta:
320321
tags = _REDACT_TAGS
321322
examples = [
322323
FunctionExample(
323-
sql="SELECT pii.redact('Call John Smith at john@example.com')",
324+
sql="SELECT pii.main.redact('Call John Smith at john@example.com')",
324325
description="Tag-redact PII (-> 'Call <PERSON> at <EMAIL_ADDRESS>')",
325326
),
326327
]
@@ -345,7 +346,7 @@ class Meta:
345346
tags = _REDACT_TAGS
346347
examples = [
347348
FunctionExample(
348-
sql="SELECT pii.redact('Call John Smith at john@example.com', 'en')",
349+
sql="SELECT pii.main.redact('Call John Smith at john@example.com', 'en')",
349350
description="Tag-redact PII with an explicit language",
350351
),
351352
]
@@ -377,7 +378,7 @@ class Meta:
377378
tags = _ANONYMIZE_TAGS
378379
examples = [
379380
FunctionExample(
380-
sql="SELECT pii.anonymize('Call John Smith at john@example.com')",
381+
sql="SELECT pii.main.anonymize('Call John Smith at john@example.com')",
381382
description="Mask PII (-> 'Call **** at ****************')",
382383
),
383384
]
@@ -402,7 +403,7 @@ class Meta:
402403
tags = _ANONYMIZE_TAGS
403404
examples = [
404405
FunctionExample(
405-
sql="SELECT pii.anonymize('Call John Smith at john@example.com', 'en')",
406+
sql="SELECT pii.main.anonymize('Call John Smith at john@example.com', 'en')",
406407
description="Mask PII with an explicit language",
407408
),
408409
]
@@ -434,7 +435,7 @@ class Meta:
434435
tags = _PII_TYPES_TAGS
435436
examples = [
436437
FunctionExample(
437-
sql="SELECT pii.pii_types('Call John Smith at john@example.com')",
438+
sql="SELECT pii.main.pii_types('Call John Smith at john@example.com')",
438439
description="The distinct PII types in text (-> ['EMAIL_ADDRESS', 'PERSON'])",
439440
),
440441
]
@@ -459,7 +460,7 @@ class Meta:
459460
tags = _PII_TYPES_TAGS
460461
examples = [
461462
FunctionExample(
462-
sql="SELECT pii.pii_types('Call John Smith at john@example.com', 'en')",
463+
sql="SELECT pii.main.pii_types('Call John Smith at john@example.com', 'en')",
463464
description="The distinct PII types in text, explicit language",
464465
),
465466
]

0 commit comments

Comments
 (0)