Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,18 @@ jobs:
name: nupkg
path: artifacts/*.nupkg
if-no-files-found: error

typesafe-pareto:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Mock tests
run: python -m unittest tools/typesafe-pareto/test_score_pareto.py -v

- name: Smoke (mock)
run: python tools/typesafe-pareto/score_pareto.py --smoke --force-mock --metrics metrics/typesafe-runs.jsonl
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ __pycache__/
venv/
.pytest_cache/

# TypeSafe / Jev live run log (regenerated by tools/typesafe-pareto)
metrics/typesafe-runs.jsonl

# Local secrets
*.pfx
appsettings.*.local.json
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/).

## [Unreleased]

### Added

- Optional **TypeSafe / Jev System One** pass (`tools/typesafe-pareto`) for Score + Choice judgments over a small Pareto candidate sample. Additive semantic layer — does not replace NSGA-III / U-NSGA-III objectives. Live calls only when `TYPESAFE_API_KEY` is set; CI uses mocks. Metrics append to `metrics/typesafe-runs.jsonl`.

## [0.1.3] — 2026-08-10

### Added
Expand Down
13 changes: 12 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Thanks for your interest. This library aims to be a **faithful, well-tested** U-

- **.NET 10 SDK** ([download](https://dotnet.microsoft.com/download))
- Optional (oracle / multi-seed stats): Python 3.10+ with `pip install pymoo`
- Optional (TypeSafe / Jev Pareto scores): Python 3.10+; live calls need `TYPESAFE_API_KEY` (never commit it)

```bash
git clone https://github.com/AppSprout-dev/Unsga3.git
Expand All @@ -34,6 +35,15 @@ python tools/oracle/run_multiseed_wilcoxon.py --problems zdt1 dtlz2 --seeds 15

See [`docs/EQUIVALENCE.md`](docs/EQUIVALENCE.md) and [`docs/ORACLE-RESULTS.md`](docs/ORACLE-RESULTS.md).

### TypeSafe / Jev Pareto scoring (optional)

```bash
python -m unittest tools/typesafe-pareto/test_score_pareto.py -v
python tools/typesafe-pareto/score_pareto.py --smoke --force-mock
```

Live System One calls run only when `TYPESAFE_API_KEY` is set. Metrics append to `metrics/typesafe-runs.jsonl` (gitignored). This path does not change algorithm defaults or oracle results.

Grok Build skills (maintainers): `/unsga3-oracle` · `/unsga3-release` under [`.grok/skills/`](.grok/skills/).

## What we welcome
Expand Down Expand Up @@ -64,7 +74,8 @@ Grok Build skills (maintainers): `/unsga3-oracle` · `/unsga3-release` under [`.
- One logical change per PR
- Update [`CHANGELOG.md`](CHANGELOG.md) under **Unreleased** when user-visible
- If you touch survival / normalization / metrics, note oracle impact (or re-run multi-seed)
- Do not commit `tools/oracle/out/` front CSVs
- Do not commit `tools/oracle/out/` front CSVs or `metrics/typesafe-runs.jsonl`
- Do not commit API keys (`.env` is gitignored; use `TYPESAFE_API_KEY` locally only)

## Reporting bugs

Expand Down
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,31 @@ dotnet run --project samples/BasicUsage -c Release

Requires **.NET 10** SDK. Optional oracle: Python 3 + `pip install pymoo` (see [CONTRIBUTING.md](CONTRIBUTING.md)).

## TypeSafe / Jev Pareto scoring (optional)

After a classical U-NSGA-III front, you can run a **TypeSafe System One** (Jev) pass over a small candidate sample and compare calibrated Score / Choice answers to raw objective vectors. This is an **additive semantic layer** — it does **not** replace NSGA-III / U-NSGA-III objectives, constraint-domination, or IGD.

The helper lives in `tools/typesafe-pareto/` (stdlib Python; official `typesafe-sdk` is optional for live calls). One `POST /v1/systemone` fans out per-candidate **Score** (`constraint_satisfaction`, `diversity_value`, `exploit_vs_explore`) and **Choice** (`keep` | `drop` | `review`). Smoke batches ≤10 fixture candidates.

```bash
# Mock (default when TYPESAFE_API_KEY is unset; what CI runs)
python tools/typesafe-pareto/score_pareto.py --smoke --force-mock

# Live Jev (key from the environment only — never commit it)
export TYPESAFE_API_KEY=... # https://docs.typesafe.ai/sdk/python.md
pip install -r tools/typesafe-pareto/requirements-optional.txt # optional SDK
python tools/typesafe-pareto/score_pareto.py --smoke
python tools/typesafe-pareto/score_pareto.py --candidates path/to/front.json
```

Candidate JSON is an object with `candidates` (or `NonDominatedSolutions`), each with `objectives` and optional `variables` / `constraints` / `constraint_violation` / `feasible` / `rank`. A synthetic ZDT1-like fixture is at `tools/typesafe-pareto/fixtures/zdt1_candidates.json`.

Metrics append one JSON line per run to **`metrics/typesafe-runs.jsonl`** (gitignored):

`{ts, experiment:"unsga3_pareto_score", repo:"AppSprout-dev/Unsga3", model, latency_ms, usage, candidate_count, answers, notes}`

API docs used: [HTTP](https://docs.typesafe.ai/api.md) · [Python SDK](https://docs.typesafe.ai/sdk/python.md) · [fan-out](https://docs.typesafe.ai/patterns/fan-out.md). No API keys in this repo.

## Equivalence & research

| Doc | Contents |
Expand All @@ -110,6 +135,8 @@ Unsga3/
├── samples/BasicUsage/
├── tools/oracle/ # pymoo oracle + multi-seed stats (optional)
├── tools/OracleCompare/ # C# side of the oracle
├── tools/typesafe-pareto/ # optional TypeSafe / Jev Score+Choice on a front sample
├── metrics/ # typesafe-runs.jsonl (local; gitignored)
├── docs/
└── .github/workflows/ # CI + GitHub Packages publish
```
Expand Down
4 changes: 3 additions & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
| 0.1.x | Yes |
| < 0.1 | No |

This is a pure numerical optimization library with **no network surface** and no default deserialization of untrusted input. Risk is mainly supply-chain (NuGet) and misuse in safety-critical decision systems.
This is a pure numerical optimization library with **no network surface** in the NuGet package and no default deserialization of untrusted input. Risk is mainly supply-chain (NuGet) and misuse in safety-critical decision systems.

The optional `tools/typesafe-pareto` helper may call `https://api.typesafe.ai/v1/systemone` when `TYPESAFE_API_KEY` is set. Do not commit API keys or `.env` files.

## Reporting a vulnerability

Expand Down
1 change: 1 addition & 0 deletions docs/NOTICE.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ See also `CITATION.cff` for citing **this** software.
|---------|-------------------|---------------|
| [pymoo](https://pymoo.org/) | Apache-2.0 | **Oracle only** — external Python scripts under `tools/oracle/` compare IGD and fronts. **Not** linked into the NuGet package. |
| NumPy / SciPy (via pymoo env) | BSD | Optional stats / oracle scripts |
| [TypeSafe](https://docs.typesafe.ai/) / Jev | hosted API | Optional `tools/typesafe-pareto` System One Score/Choice pass. **Not** linked into the NuGet package; live calls need a local `TYPESAFE_API_KEY`. |

No pymoo or SciPy code is vendored in `src/`.

Expand Down
Empty file added metrics/.gitkeep
Empty file.
82 changes: 82 additions & 0 deletions tools/typesafe-pareto/fixtures/zdt1_candidates.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
{
"problem": "zdt1",
"algorithm": "U-NSGA-III",
"source": "synthetic-fixture",
"notes": "Synthetic ZDT1-like points for TypeSafe / Jev smoke. Pareto-optimal ZDT1 satisfies f2 = 1 - sqrt(f1).",
"candidates": [
{
"id": "c0",
"variables": [0.0],
"objectives": [0.0, 1.0],
"constraints": [],
"constraint_violation": 0.0,
"feasible": true,
"rank": 0
},
{
"id": "c1",
"variables": [0.1],
"objectives": [0.1, 0.6838],
"constraints": [],
"constraint_violation": 0.0,
"feasible": true,
"rank": 0
},
{
"id": "c2",
"variables": [0.25],
"objectives": [0.25, 0.5],
"constraints": [],
"constraint_violation": 0.0,
"feasible": true,
"rank": 0
},
{
"id": "c3",
"variables": [0.5],
"objectives": [0.5, 0.2929],
"constraints": [],
"constraint_violation": 0.0,
"feasible": true,
"rank": 0
},
{
"id": "c4",
"variables": [0.75],
"objectives": [0.75, 0.134],
"constraints": [],
"constraint_violation": 0.0,
"feasible": true,
"rank": 0
},
{
"id": "c5",
"variables": [1.0],
"objectives": [1.0, 0.0],
"constraints": [],
"constraint_violation": 0.0,
"feasible": true,
"rank": 0
},
{
"id": "c6",
"variables": [0.5],
"objectives": [0.5, 0.6],
"constraints": [],
"constraint_violation": 0.0,
"feasible": true,
"rank": 1,
"notes": "Dominated / off-front: ZDT1 PF at f1=0.5 is f2≈0.2929"
},
{
"id": "c7",
"variables": [0.4],
"objectives": [0.4, 0.3675],
"constraints": [0.25],
"constraint_violation": 0.25,
"feasible": false,
"rank": 0,
"notes": "Infeasible (g>0); included so constraint_satisfaction has a negative case"
}
]
}
3 changes: 3 additions & 0 deletions tools/typesafe-pareto/requirements-optional.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Live System One calls only. CI and --force-mock use stdlib + fixtures.
# Docs: https://docs.typesafe.ai/sdk/python.md
typesafe-sdk
Loading
Loading