feat(prolog): adapt resolution to IntentFrame with canonical semantic corpus (#156) #280

Closed
nsaspy wants to merge 0 commits from rage/156-prolog-frames into master
Owner

Summary

Implements #156 against the frozen IntentFrame v1 contract (#154), completing the semantic chain started by #155 (clarification sessions, PR #236).

  • modules/intent_frames.pl — new pure resolve_frames/4: fresh resolution + follow-up context mode (partial_frame(Frame, Missing)), per-intent typed slot schemas, deterministic timer precedence mirroring legacy memberchk(timer), verb_intent-first head selection, correction markers ("actually 5 minutes" -> origin correction), ambiguity choice against alternatives, cancellation phrases -> conversation.cancel, bounded slot text (512 chars). Portable subset only (compounds + lists; no dicts — Trealla-safe for #172).
  • kb/semantic_corpus.pl — one canonical declarative corpus (40 cases) covering the issue's minimum examples: timer complete/pending/correction/cancel/zero/negative/huge, open/text pending, search + todo skills, screenshot/device capability, quoted literals, injection-inert slot text, question/conversation non-hijack, unicode/punctuation/empty boundaries, dialogue context cases. Tags include known_defect_*/known_behavior_* markers so later slices flip expectations deliberately.
  • zara/prolog_engine.py — typed resolve_frames() compatibility boundary decoding into the zara/runtime/frames.py mirrors, plus encode_frame_term for host-built contexts. pyswip's nested-compound stringification is handled via flat frame_head_row/9/frame_slot_row/8 projections (atoms/ints/lists-of-atoms only).
  • kb/intents.pl — verb_intent(screenshot, screenshot, 0) so "take a screenshot" projects to device/screen.capture (KB stays the single verb authority).
  • Legacy resolve_intent/adapt_intent_result path preserved and isolated; old fixtures map identically (adapter test). Documented intentional migrations: bare "set a timer" now yields a typed missing-duration frame instead of None->LLM; "search todos milk" omits the todo word in the task/query slot.
  • No dynamic goals from user strings; #122 rewrite stays strictly upstream input.

Closes #156

Test plan

  • 86 corpus tests: every case asserted against its checked-in expected frame plus repeated-run determinism; structural mirror tests pin typed decodes (origin follow_up/correction, missing lists, ref kinds).
  • 10 adapter tests: typed mirror output, follow-up completion, correction replacement, context round-trip via encoded partial_frame, state validation, empty/whitespace, bounded text, injection safety, legacy equivalence.
  • Full local gate: scripts/test-all.sh 10/10 phases, nix flake check green, nix build green.
## Summary Implements #156 against the frozen IntentFrame v1 contract (#154), completing the semantic chain started by #155 (clarification sessions, PR #236). - `modules/intent_frames.pl` — new pure `resolve_frames/4`: fresh resolution + follow-up context mode (`partial_frame(Frame, Missing)`), per-intent typed slot schemas, deterministic timer precedence mirroring legacy `memberchk(timer)`, `verb_intent`-first head selection, correction markers ("actually 5 minutes" -> origin correction), ambiguity choice against alternatives, cancellation phrases -> `conversation.cancel`, bounded slot text (512 chars). Portable subset only (compounds + lists; no dicts — Trealla-safe for #172). - `kb/semantic_corpus.pl` — one canonical declarative corpus (40 cases) covering the issue's minimum examples: timer complete/pending/correction/cancel/zero/negative/huge, open/text pending, search + todo skills, screenshot/device capability, quoted literals, injection-inert slot text, question/conversation non-hijack, unicode/punctuation/empty boundaries, dialogue context cases. Tags include `known_defect_*`/`known_behavior_*` markers so later slices flip expectations deliberately. - `zara/prolog_engine.py` — typed `resolve_frames()` compatibility boundary decoding into the `zara/runtime/frames.py` mirrors, plus `encode_frame_term` for host-built contexts. pyswip's nested-compound stringification is handled via flat `frame_head_row/9`/`frame_slot_row/8` projections (atoms/ints/lists-of-atoms only). - `kb/intents.pl` — `verb_intent(screenshot, screenshot, 0)` so "take a screenshot" projects to `device/screen.capture` (KB stays the single verb authority). - Legacy `resolve_intent`/`adapt_intent_result` path preserved and isolated; old fixtures map identically (adapter test). Documented intentional migrations: bare "set a timer" now yields a typed missing-duration frame instead of None->LLM; "search todos milk" omits the todo word in the task/query slot. - No dynamic goals from user strings; #122 rewrite stays strictly upstream input. Closes #156 ## Test plan - 86 corpus tests: every case asserted against its checked-in expected frame plus repeated-run determinism; structural mirror tests pin typed decodes (origin follow_up/correction, missing lists, ref kinds). - 10 adapter tests: typed mirror output, follow-up completion, correction replacement, context round-trip via encoded partial_frame, state validation, empty/whitespace, bounded text, injection safety, legacy equivalence. - Full local gate: `scripts/test-all.sh` 10/10 phases, `nix flake check` green, `nix build` green.
nsaspy closed this pull request 2026-09-04 23:09:08 +00:00
Some checks failed
CI / test (pull_request) Failing after 8s
CI / android skeleton gate (pull_request) Failing after 4s
CI / shared mic / Arch Linux (pull_request) Failing after 8m45s
CI / shared mic / Ubuntu 24.04 (pull_request) Failing after 6m2s

Pull request closed

Sign in to join this conversation.
No description provided.