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
60 changes: 36 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,24 @@ curl -fsSL https://raw.githubusercontent.com/maxjustships/nomnomcli/main/install
| sh -s -- --status-json
```

The structured `status` is `installed_and_ready`, `installed_needs_provider_setup`,
`installed_path_repair_needed`, or `error`, with the executable, version, and a concrete repair or
error action when needed. No credential value is emitted. `--dry-run` remains available.
The structured `status` is `installed_base_ready`, `installed_and_ready`,
`installed_path_repair_needed`, or `error`. A healthy no-token install is
`installed_base_ready`; `installed_and_ready` is reserved for configured, reachable USDA enhanced
coverage. JSON also reports `generic_coverage` as `base` or `enhanced` and an
`optional_usda_setup` action when relevant. PATH repair remains the top-level status while retaining
those capability fields. No credential value is emitted. `--dry-run` remains available.

Check the optional generic-food connection without a prompt:

```sh
nomnom setup --status --json
```

If it reports `setup_required`, run `nomnom setup` once in your own interactive terminal. Base
product/barcode and existing local-cache capture still work when this is deferred. Setup explains
why no-label generic-food lookup needs USDA, links to the official free signup page, validates the
key before saving, and prints a final `Connected` receipt. It never opens a browser by itself.
Without a key it reports `status: base_ready` and `generic_coverage: base`; base cache, aliases,
OFF barcode/full-text, and source-backed label capture are ready. USDA provides optional broader no-photo generic/raw-food coverage. A configured and reachable key reports `status: connected` and
`generic_coverage: enhanced`. Run `nomnom setup` only when that broader coverage is wanted or a
specific food cannot be safely resolved. Setup validates the key before saving and never opens a
browser by itself.

USDA credentials are local user configuration, never repository or database content. The default
path is `$XDG_CONFIG_HOME/nomnomcli/config.toml` or `~/.config/nomnomcli/config.toml`, written with
Expand All @@ -73,15 +77,16 @@ Resolution is deterministic and ordered:
1. exact phrase in the user's alias table, pointing to an exact local cache name;
2. exact match in the user's `food_cache`;
3. token-overlap search in that cache;
4. Open Food Facts free-text search;
4. strict Open Food Facts free-text search;
5. a safe USDA FoodData Central generic proxy, when a setup key or
`NOMNOM_USDA_KEY` is configured;
6. actionable JSON error—never a guessed food.

Open Food Facts candidates need at least 0.5 normalized token overlap between the query and
product name plus brands. A category/type conflict is rejected. All kcal, protein, fat, and carbs
values must be present, finite, and greater than zero. A rejected result returns
`off_low_confidence` with the candidate and alternatives, and is neither cached nor logged.
Open Food Facts candidates need complete normalized query-token coverage from the returned product
name/brand, a matching food type/category, a source identity/barcode, and complete positive finite
kcal, protein, fat, and carbs. A branded source identity is cached as `exact_product`; an unbranded
source identity is truthfully cached as `generic_proxy` and remains subject to the configured proxy
policy. Rejected results are neither cached nor logged.

Successful API results are cached in the user's database, so the same food can resolve locally
later. Existing cache records, logs, recipes, and aliases are preserved when v0.4 opens the
Expand All @@ -96,12 +101,13 @@ nomnomcli User-Agent. API v2 search is structured/filter-only: nomnom never send
intentional because this small provider contract remains explicit and replay-testable.

Both OFF capabilities use bounded backoff for HTTP 429 and 5xx responses and safely honor a
numeric, bounded `Retry-After`. If v1 remains unavailable after retries, free-text resolution raises
the typed retryable error `openfoodfacts_unavailable`; it does not silently change endpoint or
return unrelated products. Product normalization and the token/category confidence checks still
apply to every v1 candidate.
numeric, bounded `Retry-After`. If v1 remains unavailable after retries, the OFF client raises the
typed retryable error `openfoodfacts_unavailable`; the no-key resolver preserves it inside
`food_needs_source.provider_error`. It never silently changes endpoint or returns unrelated
products. Product normalization and the token/category confidence checks still apply to every v1
candidate.

### Enable USDA fallback
### Optional USDA enhancement

Check first, then run the one-time guided connection only if needed:

Expand All @@ -119,10 +125,15 @@ environment:
export NOMNOM_USDA_KEY="your-key"
```

Without a key, a food that OFF cannot resolve returns `usda_key_required`, the setup command, and
the same signup URL. USDA search requires complete positive kcal/protein/fat/carbs, scores query
token overlap together with data type and category, prefers Foundation and SR Legacy, and enforces
a confidence floor. Weak matches return `usda_low_confidence` with candidate alternatives and are
Without a key, a food that OFF cannot safely resolve returns `food_needs_source`, not a provider-key
failure. Its first-screen actions offer a package photo, barcode, source-backed `capture label`, and
the user's local cache/aliases. USDA appears separately as an optional enhancement for broader
no-photo generic/raw-food coverage. The nested `provider_error` preserves OFF candidate,
alternatives, retryability, and other technical diagnostics. Nothing unsafe is cached or logged.

When enabled, USDA search requires complete positive kcal/protein/fat/carbs, scores query token
overlap together with data type and category, prefers Foundation and SR Legacy, and enforces a
confidence floor. Weak matches return `usda_low_confidence` with candidate alternatives and are
never cached.

The default generic policy is `allow_for_unbranded`. A USDA result becomes a generic proxy only
Expand Down Expand Up @@ -251,12 +262,13 @@ food names.
Add `--json` for stable machine-readable output. User-correctable failures are written to stderr as
an `error` object and exit with status 2. Important codes include:

- `off_low_confidence`: inspect `candidate` and `alternatives`; retry more specifically or pin a
verified label.
- `food_needs_source`: use the returned photo, barcode, label-capture, or local-cache path; inspect
nested `provider_error` for OFF diagnostics. USDA is an explicitly optional enhancement.
- `off_low_confidence`: retained as nested technical detail when OFF candidates fail strict safety
checks.
- `usda_low_confidence`: inspect the FDC candidate/data type/category and retry more specifically;
no near match was cached.
- `usda_invalid_nutrition`: every USDA candidate lacked one or more complete positive core values.
- `usda_key_required`: configure the free FDC key or pin verified values.
- `generic_proxy_confirmation_required`: show the named USDA candidate and ask before changing the
configured policy; nothing was cached or logged.
- `exact_resolution_required`: request the barcode or a package photo for source-backed capture.
Expand Down
114 changes: 114 additions & 0 deletions docs/plans.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,119 @@
# Plans

## Issue #23 Source
- Task: Make no-key base mode a successful safe product and USDA an optional coverage enhancement.
- Canonical input: GitHub issue #23 and the user's strict TDD, smoke, commit, and no-push requirements.
- Repo context: onboarding/status, installer, resolver errors and OFF provenance, tests, README, and agent skill.
- Last updated: 2026-07-21

## Issue #23 Assumptions
- OFF barcode lookup, source-backed label capture, user cache, and aliases define useful base coverage even when OFF full-text or USDA is unavailable.
- `installed_and_ready` requires both a configured and reachable USDA provider; every other verified install is `installed_base_ready` unless login PATH repair takes priority.
- Unbranded high-confidence OFF results may retain `exact_product` when source identity is a real named product, or become `generic_proxy` when the source product identity is generic; brand/SKU queries never receive a generic proxy.
- Tests and installer smoke use only checkout-local artifacts and local network stubs; no public install or live provider request is allowed.

## Issue #23 Milestone Order
| ID | Title | Depends on | Status |
| --- | --- | --- | --- |
| M17 | Freeze base/enhanced setup and doctor contracts | M16 | [x] |
| M18 | Make fresh installer completion base-ready | M17 | [x] |
| M19 | Implement safe no-key OFF resolution and actionable source errors | M18 | [x] |
| M20 | Update installation/agent UX and run release verification | M19 | [x] |

## M17. Freeze base/enhanced setup and doctor contracts `[x]`
### Goal
- No-key status is `base_ready` with base generic coverage and explicitly optional USDA enhancement; reachable configured USDA is connected/enhanced.

### Tasks
- [x] Add and witness RED setup/status capability tests.
- [x] Implement the minimal additive capability model and interactive optional-enhancement copy.
- [x] Preserve credential redaction and independent OFF capability reporting.

### Definition of Done
- Setup JSON and text treat the no-key product as ready and disclose enhanced coverage without portraying base as failed.

### Validation
```sh
PYTHONPATH=. pytest -q tests/test_config.py tests/test_cli.py
```

### Known Risks
- Doctor JSON is consumed by the shell installer, so fields must remain additive and parseable.

### Stop-and-Fix Rule
- Record RED before onboarding implementation; repair focused regressions before M18.

## M18. Make fresh installer completion base-ready `[x]`
### Goal
- A verified no-token install succeeds as `installed_base_ready`, while reachable USDA is `installed_and_ready` and PATH repair remains highest priority.

### Tasks
- [x] Add and witness RED installer JSON/human and agent-isolation contracts.
- [x] Add base/enhanced coverage and optional setup information without weakening sanitized verification.
- [x] Keep genuine installation/verification failures as `error`.

### Definition of Done
- Installer tests cover no-key, enhanced, PATH repair, malformed doctor JSON, and inherited-agent isolation.

### Validation
```sh
PYTHONPATH=. pytest -q tests/test_install.py
```

### Known Risks
- POSIX shell JSON construction must remain valid for multiline doctor output and constrained utility PATHs.

### Stop-and-Fix Rule
- Do not change installer behavior until its new status contract is observed RED.

## M19. Implement safe no-key OFF resolution and actionable source errors `[x]`
### Goal
- Strict high-confidence OFF results resolve with truthful provenance; unsafe or unavailable results return one no-key-first `food_needs_source` action contract.

### Tasks
- [x] Add and witness RED tests for exact/generic OFF identity, weak/wrong-type, unavailable OFF, and brand/SKU denial.
- [x] Preserve category/token/core-nutrient thresholds and prevent rejected candidates from cache/log writes.
- [x] Replace first-screen raw USDA-key failures with photo, barcode, label capture, cache, and optional-USDA guidance.

### Definition of Done
- No-key users either receive a safe source-backed food or a structured actionable source request; no generic brand substitution occurs.

### Validation
```sh
PYTHONPATH=. pytest -q tests/test_off.py tests/test_foods.py tests/test_cli.py tests/test_capture.py
```

### Known Risks
- Existing tests intentionally preserve the pine-nuts/cheese incident and may not be weakened.

### Stop-and-Fix Rule
- Any unsafe candidate acceptance, failed-write side effect, or provenance ambiguity blocks M20.

## M20. Update installation/agent UX and run release verification `[x]`
### Goal
- Documentation makes no-token installation a successful completion and the checkout passes every requested gate and disposable installer smoke.

### Tasks
- [x] Update README and `skill/SKILL.md` installation/limitation language.
- [x] Run full pytest, Ruff, diff audit, and checkout-import verification.
- [x] Run a disposable user-level installer against this PR source with temp HOME/tool bins and local provider stubs, then create one scoped conventional commit.

### Definition of Done
- Exact outputs are recorded in status/final notes; one local commit exists; nothing is pushed and no PR is opened.

### Validation
```sh
PYTHONPATH=. pytest -q
ruff check .
git diff --check
```

### Known Risks
- Installer source selection must be overridden locally without changing the production public source contract.

### Stop-and-Fix Rule
- Do not commit until all gates and the literal fresh no-key smoke pass.

## Issue #19 Source
- Task: Implement the v0.4 zero-friction source-backed capture slice.
- Canonical input: GitHub issue #19 plus the user's explicit default-policy override.
Expand Down
15 changes: 13 additions & 2 deletions docs/status.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Status

## Snapshot
- Current phase: issue #19 complete
- Current phase: issue #23 complete
- Plan file: `docs/plans.md`
- Status: green
- Last updated: 2026-07-21
Expand All @@ -17,14 +17,18 @@
- Passed 72 tests, Ruff, version 0.2.0, and the exact isolated v0.2 smoke; removed the `/tmp` smoke database.
- Completed v0.4 source-backed capture: safe default USDA generic proxies, exact OFF v2 barcode capture, agent-extracted label capture, durable provenance, and additive schema-v4 migration.
- Passed 155 tests, Ruff, diff audit, and the literal isolated schema-v4 capture/alias/offline-log/error smoke.
- Completed issue #23 no-key base mode: base/enhanced capability states, successful no-token installer status, strict truthful OFF exact/generic provenance, and actionable `food_needs_source` fallbacks.
- Passed 177 tests, Ruff, checkout-import guard, shell syntax, and the disposable checkout-built installer/provider-stub smoke.

## In Progress
- None.

## Next
- None; issue #19 is complete and committed locally with no push or PR.
- None; issue #23 is complete and ready for the requested local commit.

## Decisions Made
- Issue #23: a healthy no-key install is complete base coverage; USDA is only an optional enhancement for broader no-photo generic/raw-food resolution.
- Issue #23: PATH repair outranks base/enhanced installer completion status, but output must still describe the available coverage.
- Default generic policy is `allow_for_unbranded`; this explicit user decision supersedes issue #19's older `ask` default.
- Generic proxy safety requires a generic USDA type, no returned brand, an FDC id, complete validated core nutrition, accepted confidence, and full query-token coverage.
- Package photo extraction stays outside the dependency-free CLI; only extracted facts and a mandatory source note enter the user database.
Expand Down Expand Up @@ -67,6 +71,10 @@ ruff check .
| 2026-07-21 | issue #19 preflight | issue, providers, resolver, schema, CLI, tests, docs, skill | `pytest -q`; repository inspection | 126 pass; clean baseline | M13 |
| 2026-07-21 | M13 | policy, proxy, capture, and migration acceptance tests | focused pytest; full local pytest | RED contracts and 4 partial-worktree failures recorded | M14 |
| 2026-07-21 | M14–M16 | config, resolver, OFF, schema, CLI, docs, skill, tests | `pytest -q`; `ruff check .`; `git diff --check`; literal temp-DB smoke | 155 pass; clean; smoke pass | local commit |
| 2026-07-21 | M17 | setup/status tests and onboarding/CLI | focused RED/GREEN pytest | RED captured; 9 setup tests pass | M18 |
| 2026-07-21 | M18 | installer statuses, capability JSON/human output, issue #22 isolation | focused RED/GREEN pytest | 10 installer tests pass before docs additions | M19 |
| 2026-07-21 | M19 | OFF identity/provenance and no-key source error | focused RED/GREEN pytest | 79 resolver/OFF/CLI/capture tests pass | M20 |
| 2026-07-21 | M20 | docs, import isolation, full suite, lint, disposable install | `pytest -q`; `ruff check .`; local offline installer smoke | 177 pass; clean; smoke pass | local commit |

## Smoke / Demo Checklist
- [x] Fresh temp DB: help/version, capture label, alias, log, and invalid structured capture error.
Expand All @@ -82,3 +90,6 @@ ruff check .
- [x] OFF free text uses v1 with no unfiltered v2 fallback.
- [x] Doctor and setup distinguish product/barcode reachability from full-text readiness.
- [x] Version and documentation report v0.4 generic-proxy and source-backed capture behavior.
- [x] Fresh no-token checkout install reports `installed_base_ready` with base coverage.
- [x] Setup reports `base_ready/base` without USDA and `connected/enhanced` with the local USDA stub.
- [x] Safe no-key miss returns `food_needs_source` with photo/barcode/label/cache options and optional USDA.
43 changes: 43 additions & 0 deletions docs/test-plan.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,48 @@
# Test Plan

## Issue #23 Source
- Task: Validate safe no-key base mode and optional USDA enhancement UX.
- Plan file: `docs/plans.md`
- Status file: `docs/status.md`
- Last updated: 2026-07-21

## Issue #23 Validation Scope
- In scope: setup/doctor capability JSON and text, installer status/human output, issue #22 agent isolation, strict OFF exact/generic identity and provenance, no-key source-needed errors, README, and agent skill.
- Out of scope: live provider traffic, public installs, bundled food data, model-derived nutrition, paid proxies, telemetry, or secret collection.

## Issue #23 Fixtures and Network Rules
- OFF and USDA behavior is injected or monkeypatched with synthetic local responses only.
- The fresh installer smoke uses a temporary HOME, temporary tool bins, the checkout under review, and local provider stubs; it must not fetch a public package.

## Issue #23 Test Levels

### Unit
- Setup capability state transitions and optional next action.
- OFF identity classification plus existing nutrient, token, type/category, and confidence guardrails.

### Integration
- No-key high-confidence OFF resolution caches truthful mode/source identity/provenance.
- Weak/wrong/unavailable OFF without USDA returns actionable `food_needs_source` without cache/log writes.
- Installer preserves sanitized environment isolation while reporting base/enhanced capability.

### End-to-End / Smoke
- Fresh temp user install resolves checkout code and reports `installed_base_ready`, setup `base_ready`, and one safe no-key unresolved-food flow.
- Configured/reachable local USDA stub reports connected/enhanced and installer `installed_and_ready`.

## Issue #23 Negative / Edge Cases
- Brand/SKU input never accepts a generic proxy.
- Pine nuts never resolve to an unrelated cheese result.
- OFF unavailability never surfaces raw `usda_key_required` as the first-screen user error.
- Login PATH repair remains the installer status even when base or enhanced capabilities are otherwise healthy.

## Issue #23 Acceptance Gates
- [x] Every relevant production behavior has a focused test witnessed RED before implementation.
- [x] `pytest -q` imports the checkout and passes.
- [x] `ruff check .`
- [x] Fresh disposable checkout-local installer smoke passes without public network/install.
- [x] `git diff --check` and scoped diff audit pass.
- [x] One local conventional commit; no push or PR.

## Issue #19 Source
- Task: Validate the v0.4 zero-friction source-backed capture slice.
- Plan file: `docs/plans.md`
Expand Down
Loading
Loading