Skip to content

docs(lechef): add beyond-chat spec with machine-checked contracts - #147

Merged
SamGu-NRX merged 2 commits into
alphafrom
obv/burst5-fridgeluck-spec-lechef
Oct 16, 2026
Merged

SamGu-NRX merged 2 commits into
alphafrom
obv/burst5-fridgeluck-spec-lechef

Conversation

@obvious-autobuild

@obvious-autobuild obvious-autobuild Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

LeChef beyond chat: spec (five jobs, cook mode, contracts, mocks)

Draft for review — do not merge. Adds docs/spec/lechef/ under alpha: the full LeChef spec (SPEC.md, assembled from SPEC-part1–5) plus a machine-checked contract pack under docs/spec/lechef/contracts/.

Human author: Sam Gu (sgu07966@gmail.com)

What changed and why

SPEC.md (17 sections) turns LeChef from a transcript with a camera into the cooking companion PR #86 §4 defines: five local-first jobs (plan, substitute, coach, adapt, remember), dedicated surfaces with chat as a fallback, a phone-authoritative proposal/receipt model, device-persisted timers, and push-to-look as the default camera direction. Key reconciliation decisions (researched from the open draft PRs):

contracts/ — six JSON Schemas (proposal, receipt, cook-step, plan, substitution, scaling-rules), nine example fixtures (including #102's frozen action-proposal.json), and check.py.


Review round 1 (post #147 independent review) — commit 9d987b3

All three findings adopted; none disputed. One directional choice, explained below.

1. HIGH — proposal envelope schema vs the #102 wire it cited — FIXED

2. LOW — corpus-naming claim not supported — FIXED

§8.3 now says the three spec-added kinds are named by this spec's registry and that no plan/swap/adaptation kind string exists in #102's corpus or ProposalTool union — the unsupported "the suite's corpus already names them" claim is gone, as is §8.1's "the suite names speculatively".

3. LOW — check.py documents a hash round-trip it didn't perform — FIXED

  • check.py now recomputes payloadHash = sha256 over the compact canonical JSON of the payload for every proposal fixture and compares (the docstring's claim, previously unchecked).
  • Receipts are matched to proposals by proposalID (a receipt citing an unknown proposal id fails), replacing hash set-membership.
  • resolve() fails loudly on an unknown $defs ref (was: silently validated as "any").
  • The shoppingList emptiness error now fires only when short lines exist (was unconditional, with a message that could be wrong).

Fail-before-fix evidence (commands and results)

  • Finding 1: after tightening the schema but before touching the fixtures, python3 contracts/check.py → exit 1: examples/proposal-substitute.json: 'snapshotRevision' is a required property + same for proposal-add-timer.json. Fixtures updated → green.
  • Finding 3 (recompute): scratch-mutating proposal-substitute.json's payloadHash to sha256:000…0 → exit 1, two errors (recompute mismatch + its receipt's hash-equality mismatch). Under the old checker the same mutation only tripped set-membership — and only because both proposals are receipt-pinned; an unreferenced invented hash passed. Stated plainly: the reviewer's "an invented hash passes" was slightly overstated for these fixtures, the substance (no recomputation, reference-blind matching) was correct and is now fixed.
  • Finding 3 (proposalID matching): mutating receipt-executed.json's proposalID to an unknown id → exit 1, references proposalID 'prop_01J9ZZZZZZ', which no proposal fixture defines.
  • Finding 3 (fail-loud $defs): pointing a schema property at #/$defs/nope → exit 1, KeyError: 'unknown $defs reference: #/$defs/nope — fix the schema, do not validate as any'.
  • Finding 1 (rename-map gate): setting the feat(lechef): shared LeChef tool layer — phone-authoritative proposals, read tools, eval harness (Part 1, M1) #102 fixture's payload kind to the already-snake_case step_advance → exit 1, payload kind 'step_advance' is missing from the §8.1 rename map.
  • Assembly invariant: SPEC.md is byte-identical to the parts pipeline (head -11 SPEC-part1.md + separators + tail -n +13 + parts 2–5), verified programmatically this round.
  • All mutations were made on scratch copies and restored; final state: check.py: 23 checks over 6 schemas and 8 fixtures / OK — all schemas and fixtures valid (was 20 checks).

What I could not check

Assumptions

Co-authored-by: obvious-autobuild[bot] <262744130+obvious-autobuild[bot]@users.noreply.github.com>

🔗 Obvious Project · 🧵 Obvious Thread · 🔀 Obvious PR Artifact

Five local-first jobs (plan, substitute, coach, adapt, remember) with
dedicated surfaces, chat as fallback, and a phone-authoritative
proposal/receipt model adopting PR #102's wire contract verbatim.
Substitutions derive role-scoped reviewed swaps from PR #114's pairs.json
with fail-closed rechecks; planning merges #52/#141/#142 over one stock
pool; privacy adopts #26's frame-cache and session-expiry findings.

contracts/: six JSON Schemas, eight fixtures, check.py (20 checks green:
schema validation, 300s TTL, payload-hash round-trip over real SHA-256
digests, plan pool conservation, nine-class allergen gate).

Co-authored-by: obvious-autobuild[bot] <262744130+obvious-autobuild[bot]@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: b07332fc-ff20-45a4-a826-fddea4571b71

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@obvious-autobuild

Copy link
Copy Markdown
Author

Independent review (Obvious, Autobuild + Max)

Verdict: changes needed — small schema/prose edits only; the spec's research claims check out almost everywhere, but the proposal envelope schema cannot validate a proposal produced by the wire contract it says it adopts verbatim, and it drops the field its own revision-binding rule needs.

Findings (by severity)

1. HIGH — proposal envelope schema is not the #102 wire it claims to adopt, and omits snapshotRevision

2. LOW — corpus-naming claim not supported

  • SPEC.md:373 — "The three spec-added kinds are named exactly as the suite's corpus already names them, so no harness mismatch is introduced". In pr-102's evaluation corpus (src/lechef/designs/*/scripts/*.json) there are zero occurrences of "plan", "swap", or "adaptation" as kind strings, and the ProposalTool union has only the six propose* tools. The claim's supporting evidence doesn't exist on the branch it cites.
  • Smallest correct fix: reword to name this spec's registry as the source of the names (or cite the actual corpus file that uses them, if one exists elsewhere).

3. LOW — check.py documents a hash round-trip it doesn't perform

  • check.py:10 (docstring cross-check 2) and the PR body say receipt payloadHash values are "computed over the canonical payloads, not invented"; the code (check.py:197-198) only checks set membership against the proposal fixtures' own hash strings and never recomputes any digest (hashlib is never imported). A proposal fixture with an invented payloadHash passes the "machine-checked" pack.
  • For the record, I recomputed both digests myself and they do reproduce: sha256 over json.dumps(payload, sort_keys=True, separators=(",",":")) yields 557d9ef5… (timer) and 3ec4d524… (swap), matching the fixtures. The fixtures are right; the checker just doesn't police it.
  • Smallest correct fix: in step 4, recompute the digest per proposal fixture and compare (and match receipts to proposals by proposalID, not just set membership). Two adjacent one-liners while in there: resolve() (check.py:147-149) silently maps an unknown $defs ref to {} (accept-anything) — fail loudly instead; and the shoppingList emptiness error fires unconditionally, so its "short lines exist" message can be wrong when no short lines exist.

What I verified (commands and results)

  • gh pr view 147 --comments / --json: draft, base alpha@0309dd11, head 615fc1b6; no human reviews; sole comment is CodeRabbit's "review skipped". gh pr checks 147: build-and-test pass (5m52s), dead-code-advisory pass (2m45s) — run 38722083500.
  • gh pr diff --name-only: 21 files, all under docs/spec/lechef/ — docs-only scope as claimed; nothing else touched.
  • Checked out head 615fc1b in a worktree; python3 contracts/check.py → check.py: 20 checks over 6 schemas and 8 fixtures / OK — all schemas and fixtures valid, exit 0, exercised the real jsonschema 4.26.0 Draft 2020-12 path; also green with jsonschema import blocked (the inline fallback validator), same 20 checks.
  • Negative controls on a scratch copy (mutate → run → restore): expiresAt +1 s → expiresAt != createdAt + 300 s; receipt hash zeroed → payloadHash does not match any proposal fixture; fitSummary.totalLines +1 → counted 4 lines, fitSummary.totalLines is 5; allergen mustard → schema enum + nine-class cross-check errors; kind add_timer → enum rejection; unknown field → additionalProperties rejection. All exit 1 — the checker's cross-checks fail when they should. check.py does not exist on origin/alpha (new-dir PR, as the body says).
  • Retired-kind sweep reproduced: no add_timer/substitute_ingredient/start_cook_session/change_quantity in SPEC*.md; suggest_recipe appears only as prose stating it is not a proposal kind (SPEC.md:332).
  • Assembly claim reproduced: cat SPEC-part1..5.md differs from SPEC.md only by the --- separators between parts.
  • Overhaul: reviewed substitution table (data milestone 1) #114 claims verified on pr-114 data/substitutions/pairs.json: schema_version 1.1.0, 279 pairs, 381 ingredients, 11 roles, 13 restrictions, 9 allergen classes, and exactly 123 of 381 ingredient records carry facts_key (258 fail closed) — SPEC.md:§6's numbers are all exact.
  • LeChef suite D: 155 scripted sessions + fail-closed scorer, real run #101/feat(data): resolve ingredient identity and compile validated bundle-v2 #158 claim: LeChef suite D: 155 scripted sessions + fail-closed scorer, real run #101's title says "155 scripted sessions"; feat(lechef): shared LeChef tool layer — phone-authoritative proposals, read tools, eval harness (Part 1, M1) #102's merged-suite body reports "158/158 sessions conform" — matching the body's "158-session corpus (despite its 155-session title)".
  • alpha@0309dd1 evidence spot-checks: LiveAssistantView.swift is 777 lines; liveSessionStore.ts:242-256 is recordLatestFrame persisting latestCameraFrame to Firestore; toolRegistry.ts has get_recipe_context (line 26) and mutate_inventory (line 96); planning/stage_0-brainstorm/fridgeluck planning.md:1205 carries the guard-rails quote verbatim.

What I couldn't verify

…enforced hash round-trip

Finding 1 (HIGH): proposal.schema.json now carries snapshotRevision
(required, integer >= 1) so §8.1's revision-binding rule has a wire field;
rationale and requiredApproval become optional (absent from #102's wire
and its frozen fixture); schema title/description state the §8.1 rename
map instead of claiming verbatim adoption. SPEC §8 intro/§8.1/§8.3/§14
reworded from 'adopted verbatim' to 'adopted and re-cut', listing #102's
actual camelCase payload kinds (timerStart..note) with the map
(top-level snake_case, note->save_note, id->prop_-prefixed proposalID,
sha256:-prefixed hash). The re-cut is kept rather than reverting to
#102's raw envelope because PR #156 is already cut to these contracts.

Finding 2 (LOW): §8.3's corpus-naming claim replaced — the three
application kinds are named by this spec's registry; #102's corpus and
ProposalTool union contain no plan/swap/adaptation kind strings.

Finding 3 (LOW): check.py now recomputes payloadHash = sha256 over the
compact canonical payload for every proposal fixture (was set-membership
only), matches receipts to proposals by proposalID, fails loudly on an
unknown $defs ref, and fires the shoppingList error only when short
lines exist. New cross-check: #102's frozen action-proposal.json fixture
(added verbatim) is mapped through the §8.1 rename map and must validate
against proposal.schema.json.

Fail-before-fix evidence in PR body; check.py 23/23 green.

Co-authored-by: obvious-autobuild[bot] <262744130+obvious-autobuild[bot]@users.noreply.github.com>
@SamGu-NRX
SamGu-NRX merged commit 6646dcc into alpha Oct 16, 2026
3 checks passed
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