Skip to content

Add govkit-synthetic-data skill (Faker-based scenario test data generator)#3

Merged
marty916 merged 1 commit into
mainfrom
add-govkit-synthetic-data-skill
Jul 8, 2026
Merged

Add govkit-synthetic-data skill (Faker-based scenario test data generator)#3
marty916 merged 1 commit into
mainfrom
add-govkit-synthetic-data-skill

Conversation

@marty916

@marty916 marty916 commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a new GovKit skill, govkit-synthetic-data, that turns an approved feature package into the synthetic test data its scenarios need: a seeded, standalone Python Faker generator plus committed data files and a coverage manifest.

The script is the deliverable, not just the data — a seeded generator regenerates byte-identical output in CI, survives schema tweaks with a one-line edit, and shows reviewers exactly how every value was produced. Faker output is inherently synthetic, which is what makes it safe in a government context.

What's included

  • plugins/govkit/skills/govkit-synthetic-data/SKILL.md — purpose, tool-agnostic design, inputs, the 5-step process (parse package → build data profile → plan coverage → write generator → run/verify/manifest), output layout, and guardrails.
  • plugins/govkit/skills/govkit-synthetic-data/references/faker-patterns.md — provider selection, locale, custom providers for domain formats, relational integrity, and edge-case injection.
  • plugins/govkit/skills/govkit-synthetic-data/scripts/generator_template.py — standalone starting-point script (single seed, stdlib + faker only, CSV/JSONL/SQL writers, --help, --seed).

Design notes

  • Tool-agnostic: the generator/project boundary is data files (CSV/JSONL/SQL), so the target stack can be C#, Java, Go, anything — only the generator itself is Python (pip install faker).
  • Coverage-driven: every dataset traces back to a scenario (or a stated NFR/schema request); default per-scenario spread covers happy (zero/one/many), boundary, negative (one violated rule each), and NFR-driven volume.
  • Deterministic: single seed via Faker.seed() + random.seed(); verified by regenerating and diffing before it's considered done.
  • Guardrails: never invents business rules the package doesn't state, never touches real production data, every record carries a synthetic marker, and every assumption is recorded in the manifest with an owner.

🤖 Generated with Claude Code

…ator)

Generate synthetic test data for a GovKit feature package from its Gherkin
scenarios: a seeded, standalone Python Faker generator script plus committed
data files and a MANIFEST coverage map tracing every dataset back to the
scenario it exercises.

- Tool-agnostic: the generator/project boundary is data files (CSV/JSONL/SQL),
  so the target stack can be anything; only the generator is Python.
- Deterministic and regenerable (single seed, stdlib + faker only), with a
  synthetic marker on every record and guardrails against inventing business
  rules or touching real production data.
- Includes SKILL.md, references/faker-patterns.md, and a standalone
  scripts/generator_template.py.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add GovKit synthetic-data skill with Faker-based deterministic generator template

✨ Enhancement 📝 Documentation 🕐 20-40 Minutes

Grey Divider

AI Description

• Add GovKit skill guidance for scenario-driven synthetic test data generation and coverage mapping.
• Document Faker patterns for determinism, domain formats, relational integrity, and edge-case
 injection.
• Provide a standalone, seeded Python generator template emitting CSV/JSONL/SQL outputs.
Diagram

graph TD
  A["GovKit skill package"] --> B[/"SKILL.md"/] --> D[["generator_template.py"]] --> E["Feature package"] --> F[("Synthetic data + MANIFEST")]
  B --> C[/"faker-patterns.md"/]

  subgraph Legend
    direction LR
    _pkg["Package/Module"] ~~~ _doc[/"Docs"/] ~~~ _script[["Script"]] ~~~ _out[("Data output")]
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Ship a GovKit CLI that scaffolds generator + manifest automatically
  • ➕ Less manual copying/customization of the template into each feature package
  • ➕ Can enforce manifest format and determinism checks consistently
  • ➖ Adds tooling surface area and maintenance burden
  • ➖ Less tool-agnostic in practice (teams must adopt the CLI workflow)
2. Use schema-first generators (e.g., JSON Schema + datagen) instead of Faker scripts
  • ➕ Constraints can be expressed formally and validated mechanically
  • ➕ Easier to evolve if the schema is the primary contract
  • ➖ Harder to map datasets back to Gherkin scenario intent and negative/boundary cases
  • ➖ May still require custom code for domain identifiers and cross-entity integrity
3. Generate fixtures/seed data in the target stack (C#/Java/Go) rather than Python
  • ➕ No Python/Faker dependency for teams that forbid it
  • ➕ Integrates naturally with existing test harnesses and ORM seeders
  • ➖ Loses the explicit tool-agnostic boundary this skill is aiming for
  • ➖ Cross-language determinism and reviewability are typically worse than a single standalone script

Recommendation: Current approach (docs + reference + a standalone seeded generator template) is a good baseline for GovKit because it preserves tool-agnostic consumption (data files) while keeping generation deterministic and reviewable. Consider adding an optional CLI scaffolder later if repeated manual setup becomes a pain point, but keep the core contract as committed generator + committed datasets + manifest.

Files changed (3) +436 / -0

Enhancement (1) +169 / -0
generator_template.pyAdd standalone seeded generator template with CSV/JSONL/SQL writers +169/-0

Add standalone seeded generator template with CSV/JSONL/SQL writers

• Introduces a runnable Python 3.9+ template that seeds Faker and stdlib random for reproducible output, writes JSONL/CSV/SQL, and demonstrates happy (zero/one/many), boundary, negative, and optional volume datasets. Enforces a per-record synthetic marker and avoids time-based nondeterminism via frozen date ranges.

plugins/govkit/skills/govkit-synthetic-data/scripts/generator_template.py

Documentation (2) +267 / -0
SKILL.mdIntroduce govkit-synthetic-data skill definition and end-to-end process +157/-0

Introduce govkit-synthetic-data skill definition and end-to-end process

• Adds a new GovKit skill document describing purpose, scope, inputs, and a 5-step workflow from parsing scenarios to generating deterministic outputs and a coverage/assumptions manifest. Defines guardrails (no real data, no invented business rules) and prescribes output layout under feature packages.

plugins/govkit/skills/govkit-synthetic-data/SKILL.md

faker-patterns.mdAdd Faker reference patterns for deterministic, scenario-aligned data generation +110/-0

Add Faker reference patterns for deterministic, scenario-aligned data generation

• Documents provider choices, determinism pitfalls (seed ordering, frozen dates, stable ordering), domain formats via bothify/numerify and custom providers, relational integrity strategies, and boundary/negative injection techniques. Provides locale guidance and how to encode distribution/state-dependent values.

plugins/govkit/skills/govkit-synthetic-data/references/faker-patterns.md

@marty916
marty916 merged commit d552b73 into main Jul 8, 2026
1 check passed
@marty916
marty916 deleted the add-govkit-synthetic-data-skill branch July 8, 2026 12:41
@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Missing run version metadata 🐞 Bug ⚙ Maintainability
Description
generator_template.py claims to be self-describing, but its header/docstring does not include the
seed or Faker version (as required by the skill instructions), reducing reproducibility/auditability
when outputs differ across environments. This makes it harder to diagnose non-byte-identical output
caused by dependency/runtime drift.
Code

plugins/govkit/skills/govkit-synthetic-data/scripts/generator_template.py[R1-14]

+#!/usr/bin/env python3
+"""Synthetic test data generator — <WORK-ITEM-ID>.
+
+Generated for the GovKit feature package at /features/<WORK-ITEM-ID>/.
+ALL OUTPUT IS SYNTHETIC (Python Faker). No real records were used.
+
+Deterministic: the same --seed always produces byte-identical output.
+Dependencies: python 3.9+ and `pip install faker` — nothing else.
+
+Usage:
+    python generate_test_data.py                 # default seed, all datasets
+    python generate_test_data.py --seed 42
+    python generate_test_data.py --outdir data/
+"""
Evidence
The skill doc explicitly requires the committed generator to be self-describing with header metadata
(seed + faker version), but the template’s docstring does not include those values.

plugins/govkit/skills/govkit-synthetic-data/SKILL.md[96-103]
plugins/govkit/skills/govkit-synthetic-data/scripts/generator_template.py[1-14]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The skill instructions say the generator template is "Self-describing" and that the header comment names the work item, seed, and Faker version, but the current template header/docstring does not include seed/version metadata.

### Issue Context
This skill’s core promise is deterministic, byte-identical regeneration. When output differs due to environment drift (Faker/Python version changes), missing metadata makes it difficult to root-cause.

### Fix Focus Areas
- plugins/govkit/skills/govkit-synthetic-data/scripts/generator_template.py[1-15]
- plugins/govkit/skills/govkit-synthetic-data/scripts/generator_template.py[143-166]

### Implementation notes
- Import and surface Faker + Python version (e.g., `import faker` / `sys`).
- Include seed + versions in the startup banner / final print, and/or write a small manifest file next to outputs.
- Update the module docstring to include the seed and to mention where version metadata is emitted.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Zero-row CSV lacks header 🐞 Bug ≡ Correctness
Description
write_csv() writes an empty file for empty datasets, but its comment says headers may be required
and there is no way to supply fieldnames without records. This can break CSV loaders/tests that
require a header row even when the dataset has zero records.
Code

plugins/govkit/skills/govkit-synthetic-data/scripts/generator_template.py[R55-62]

+def write_csv(records: list, path: Path) -> None:
+    path.parent.mkdir(parents=True, exist_ok=True)
+    if not records:
+        # An intentionally empty dataset still gets written so loaders can
+        # detect the zero-cardinality case. Supply columns explicitly if a
+        # header row is required.
+        path.write_text("", encoding="utf-8")
+        return
Evidence
The function explicitly writes an empty string for empty datasets, while also acknowledging headers
might be required; there is no parameter to provide column names in the empty case.

plugins/govkit/skills/govkit-synthetic-data/scripts/generator_template.py[55-62]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`write_csv()` cannot emit a header row for empty datasets, yet the template explicitly supports zero-cardinality datasets and the function comment notes headers may be required.

### Issue Context
Many CSV consumers are schema-driven and expect headers even when there are 0 rows. The template currently produces an empty file which can be ambiguous or fail parsing.

### Fix Focus Areas
- plugins/govkit/skills/govkit-synthetic-data/scripts/generator_template.py[55-69]

### Implementation notes
- Add an optional `fieldnames: list[str] | None = None` parameter.
- If `records` is empty and `fieldnames` is provided, write a header-only CSV.
- Consider adding a small example usage in `main()` or comments showing how to emit a header-only zero dataset.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Volume dataset built in-memory 🐞 Bug ➹ Performance
Description
The volume path builds args.volume records into a Python list before writing, which scales peak
memory linearly with the requested dataset size. For NFR-driven volumes, this can cause slowdowns or
OOM failures in CI.
Code

plugins/govkit/skills/govkit-synthetic-data/scripts/generator_template.py[R162-163]

+    if args.volume:
+        write_csv(happy_records(fake, args.volume), out / "example_volume.csv")
Evidence
The skill documentation calls out NFR-driven volume datasets, and the template implements volume
generation by creating a list of all records (happy_records) before writing, which directly
increases memory usage with volume size.

plugins/govkit/skills/govkit-synthetic-data/SKILL.md[71-72]
plugins/govkit/skills/govkit-synthetic-data/scripts/generator_template.py[115-117]
plugins/govkit/skills/govkit-synthetic-data/scripts/generator_template.py[162-164]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The template materializes the entire volume dataset in memory via `happy_records(..., args.volume)` before writing CSV.

### Issue Context
This skill explicitly supports NFR-driven scale datasets; those counts can be large. Holding all records in RAM is unnecessary for CSV/JSONL writing and can fail in CI.

### Fix Focus Areas
- plugins/govkit/skills/govkit-synthetic-data/scripts/generator_template.py[115-117]
- plugins/govkit/skills/govkit-synthetic-data/scripts/generator_template.py[162-164]

### Implementation notes
- Change `happy_records` to yield records (iterator/generator) or add `iter_happy_records`.
- Update `write_csv` (and optionally `write_jsonl`) to accept an iterable and write incrementally.
- For CSV streaming, write header from a single "first" record, then write the first + subsequent records without building a full list.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment on lines +1 to +14
#!/usr/bin/env python3
"""Synthetic test data generator — <WORK-ITEM-ID>.

Generated for the GovKit feature package at /features/<WORK-ITEM-ID>/.
ALL OUTPUT IS SYNTHETIC (Python Faker). No real records were used.

Deterministic: the same --seed always produces byte-identical output.
Dependencies: python 3.9+ and `pip install faker` — nothing else.

Usage:
python generate_test_data.py # default seed, all datasets
python generate_test_data.py --seed 42
python generate_test_data.py --outdir data/
"""

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

1. Missing run version metadata 🐞 Bug ⚙ Maintainability

generator_template.py claims to be self-describing, but its header/docstring does not include the
seed or Faker version (as required by the skill instructions), reducing reproducibility/auditability
when outputs differ across environments. This makes it harder to diagnose non-byte-identical output
caused by dependency/runtime drift.
Agent Prompt
### Issue description
The skill instructions say the generator template is "Self-describing" and that the header comment names the work item, seed, and Faker version, but the current template header/docstring does not include seed/version metadata.

### Issue Context
This skill’s core promise is deterministic, byte-identical regeneration. When output differs due to environment drift (Faker/Python version changes), missing metadata makes it difficult to root-cause.

### Fix Focus Areas
- plugins/govkit/skills/govkit-synthetic-data/scripts/generator_template.py[1-15]
- plugins/govkit/skills/govkit-synthetic-data/scripts/generator_template.py[143-166]

### Implementation notes
- Import and surface Faker + Python version (e.g., `import faker` / `sys`).
- Include seed + versions in the startup banner / final print, and/or write a small manifest file next to outputs.
- Update the module docstring to include the seed and to mention where version metadata is emitted.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +55 to +62
def write_csv(records: list, path: Path) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
if not records:
# An intentionally empty dataset still gets written so loaders can
# detect the zero-cardinality case. Supply columns explicitly if a
# header row is required.
path.write_text("", encoding="utf-8")
return

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

2. Zero-row csv lacks header 🐞 Bug ≡ Correctness

write_csv() writes an empty file for empty datasets, but its comment says headers may be required
and there is no way to supply fieldnames without records. This can break CSV loaders/tests that
require a header row even when the dataset has zero records.
Agent Prompt
### Issue description
`write_csv()` cannot emit a header row for empty datasets, yet the template explicitly supports zero-cardinality datasets and the function comment notes headers may be required.

### Issue Context
Many CSV consumers are schema-driven and expect headers even when there are 0 rows. The template currently produces an empty file which can be ambiguous or fail parsing.

### Fix Focus Areas
- plugins/govkit/skills/govkit-synthetic-data/scripts/generator_template.py[55-69]

### Implementation notes
- Add an optional `fieldnames: list[str] | None = None` parameter.
- If `records` is empty and `fieldnames` is provided, write a header-only CSV.
- Consider adding a small example usage in `main()` or comments showing how to emit a header-only zero dataset.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +162 to +163
if args.volume:
write_csv(happy_records(fake, args.volume), out / "example_volume.csv")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

3. Volume dataset built in-memory 🐞 Bug ➹ Performance

The volume path builds args.volume records into a Python list before writing, which scales peak
memory linearly with the requested dataset size. For NFR-driven volumes, this can cause slowdowns or
OOM failures in CI.
Agent Prompt
### Issue description
The template materializes the entire volume dataset in memory via `happy_records(..., args.volume)` before writing CSV.

### Issue Context
This skill explicitly supports NFR-driven scale datasets; those counts can be large. Holding all records in RAM is unnecessary for CSV/JSONL writing and can fail in CI.

### Fix Focus Areas
- plugins/govkit/skills/govkit-synthetic-data/scripts/generator_template.py[115-117]
- plugins/govkit/skills/govkit-synthetic-data/scripts/generator_template.py[162-164]

### Implementation notes
- Change `happy_records` to yield records (iterator/generator) or add `iter_happy_records`.
- Update `write_csv` (and optionally `write_jsonl`) to accept an iterable and write incrementally.
- For CSV streaming, write header from a single "first" record, then write the first + subsequent records without building a full list.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

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.

1 participant