Skip to content

feat(mbse): vendor requirements semantic model from kr0ki-core (M1) - #28

Merged
elasticdotventures merged 1 commit into
mainfrom
feat/mbse-requirements
Sep 19, 2026
Merged

elasticdotventures merged 1 commit into
mainfrom
feat/mbse-requirements

Conversation

@elasticdotventures

Copy link
Copy Markdown
Member

Summary

  • Vendors kr0ki-core's backend-neutral ReqIF/Flexo requirements model (RequirementGraph, five induced viewpoints, asserted/inferred/proposed relation authority + explicit promotion) into mbse::requirements as the canonical shared contract.
  • kr0ki-core re-exports ufo_types::mbse::requirements as kr0ki_core::requirements rather than keeping a local copy — single source of truth, zero drift, zero duplication.
  • Per PromptExecution/kr0ki docs/HANDOFF-2026-09-19-reqif-flexo.md, lead-developer action ci: add standalone ufo-types quality gate #1.
  • Version bump 0.14.1 → 0.15.0 (additive public API; pre-1.0 minor per this crate's own stability policy).

Test plan

  • cargo test --all-features — 261 passed
  • cargo clippy --all-targets --all-features -- -D warnings — clean
  • cargo fmt --check — clean

Moves kr0ki-core's backend-neutral ReqIF/Flexo requirements model
(RequirementGraph, five induced viewpoints, asserted/inferred/proposed
relation authority with explicit promotion) into mbse::requirements as
the shared canonical contract, per HANDOFF-2026-09-19-reqif-flexo.md
lead-developer action #1. kr0ki-core re-exports it rather than keeping
a local copy — single source of truth, zero drift.

Version bump to 0.15.0 (additive public API, pre-1.0 minor per this
crate's own stability policy).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CJ5M1bGQJB1VS8Epr7AGLa
@elasticdotventures
elasticdotventures merged commit a17bf74 into main Sep 19, 2026
2 checks passed
@elasticdotventures
elasticdotventures deleted the feat/mbse-requirements branch September 19, 2026 19:25
elasticdotventures added a commit to PromptExecution/kr0ki that referenced this pull request Sep 19, 2026
… ufo-types) (#36)

* feat: storyb00k projects — planning stage, refinement questions, full transparency

Cherry of 249837b onto post-#34 main:
- project_store.py: per-thread project (title/goal/requirements/locked, verbatim
  prompt log, LLM thinking log, QA history) persisted beside charts; endpoints
  GET /projects[/{id}], POST /projects/rename
- ask_user tool: multiple-choice refinement questions as AG-UI interrupts
  (options ride responseSchema defaults); answers recorded as QA, run continues
- system prompt workflow: THINK → ASK → 'Locked in:' → RENDER; server-side lock detection
- THINKING_* events: reasoning_content as 💭 thinking blocks, captured server-side
- UI: project banner (editable title, locked badge, QA, expandable prompt+thinking log)
- live E2E verified: 2 refinement rounds -> locked in -> k8s panel rendered
- tests: 38 python, 15 vitest

* fix: emit full TOOL_CALL lifecycle before ask_user/propose interrupts

The client's state machine rejects TOOL_CALL_END/RESULT without a prior
TOOL_CALL_START ('No active tool call found'), aborting the run before the
interrupt reached the UI. ask_user now emits START → ARGS → END → RESULT;
propose_draft_change (which emitted no tool-call events at all) gets the
same lifecycle. Validated 6/6 against the @ag-ui/core event union; live
verified: question interrupt now reaches the browser and answers flow.

* fix(storyb00k): inline answer UI, no auto-resume collision, dark-theme inputs

- autoResumeInterrupts: false — the client's auto-resume fired resume() the
  moment an interrupt was answered, colliding with our explicit chat.send()
  ('A run is already in progress'); continuation is now driven solely by
  submitAnswer()
- question + options render immediately (no 'Answer question' gate click);
  submitAnswer targets the interrupt by id
- dark theme: composer/prompt-editor/freetext/project-title inputs got UA
  white defaults on the dark app — now #091127 bg + #edf5ff text; message
  bubbles, interrupt cards, error/lock/requirement chips re-themed to match
  the app's palette

* fix(playbook): tab renamed storyb00k -> Agent; editor hero copy cut to one line

'storyb00k' is an internal codename and stays out of the UI nav; the editor
view's header paragraph was a wall of text — now one sentence.

* fix(storyb00k): resume() instead of send() after answering; sidebar copy trimmed

- answering an ask_user interrupt now calls chat.resume(), which replays the
  interrupted run with the recorded response — chat.send() started a fresh
  run and the agent rejected it ('Thread has N pending interrupt(s) not
  addressed by resume')
- sidebar copy: 'Example fixtures for every supported format — or clear the
  source and render your own.' (internal jargon out)

* fix(storyb00k): project memory prevents re-asking answered questions

The client replays identical messages on resume, so the LLM never saw the
answer and re-asked. Each run now injects answered QA (and any locked-in
requirements) into the system prompt as PROJECT MEMORY — 'never ask the same
or an equivalent question again' — and appends unanswered QA as explicit user
turns. 39/39 python (new regression test captures the second run's LLM
messages and asserts the memory + answer turn are present).

* docs: PLAN-KR0KI-005 — gallery catalog & type-discovery agent spec

Intent-first ergonomics: users don't know the diagram type they need. Gallery
browse-by-use-case (filter defaults to All, distinct addressible typeIds,
per-card Agent button pre-filling a typed sample prompt); agent 'discover'
question series (audience -> intent shape -> fidelity -> recommend 1+1 ->
confirm, with visual 'show me both') parallel to requirement refinement; type
lock-in into PROJECT MEMORY; per-syntax skills loaded only when the type is
locked.

* feat: Plan 005 — gallery catalog, type-discovery agent, per-type skills

Step 1 catalog: kr0ki-core/src/catalog.rs — 24 addressible diagram types with
intent tags from a controlled vocabulary, sample prompts naming the type,
discovery guide; /api/catalog route (+http test); 6 unit tests.

Step 2 gallery: intent filter bar (defaults to All, auto-resets), type cards
with Test/Edit/Agent buttons; Agent handoff prefills the Agent composer with
the type's sample prompt (never auto-sent) via forwardedProps-ready prop.

Step 3 discover mode: recommend_diagram_type tool — agent must commit to 1–2
type recommendations with rationales after ≤3 intent questions; confirm
interrupt locks lockedType into the project; REFINE vs DISCOVER mode rules in
the system prompt; project memory carries 'Type chosen: …'.

Step 4 skills: skills/types/{sequence,activity,erd,component}.md loaded ONLY
when the type is locked (replaces generic dump).

Gates: 40/40 python, 15/15 vitest, 19/19 cargo suites, just check clean.
Live acceptance: alert→resolution prompt with no syntax named → 2 discovery
questions → recommend interrupt (State diagram | Flowchart | Show me both) →
confirm locks type → next run is refine-mode with Locked in: summary.

* fix(storyb00k): rec-* interrupts render the answer UI; approval payloads tolerated

A recommend_diagram_type interrupt (rec-*) fell into the generic
Approve-draft branch because isQuestionInterrupt only matched ask-* —
posting {approved: true} to a question endpoint 400s. rec-* now renders the
multiple-choice UI like ask-*; and the server tolerates approval-style
payloads on question interrupts by choosing the primary option. 41/41
python.

* style(gallery): filter bar redesign

Pill-tab strip in a bordered tray: 'I want to show' label, hover/focus
states, gradient active pill with glow, per-tag type counts, aria-pressed,
and an empty-state when a filter matches nothing.

* fix(gallery): type-card renders are card-scoped, not example-scoped; headline trimmed

Ten PlantUML types share one fixture, so keying Test artifacts by example id
lit up every PlantUML card at once. Type cards now use their own
typeStatus/typeArtifacts/typeErrors maps keyed by typeId. Hero headline cut
to 'Diagram-as-code, rendered.'

* feat(storyb00k): fast-track 'Diagram now' + generation spinner

- After 2 answered questions the project banner offers '⚡ Diagram now':
  arms fast-track server-side (POST /projects/fasttrack) and sends a
  best-judgement instruction. Fast-track overrides the question-mode rules
  entirely (FAST-TRACK MODE: asking is a contract violation); the agent
  states 'Best judgement:' choices and renders in the same run.
- Dashboard shows a spinner + 'Generating diagram…' while a run streams,
  next to the panel count.
- Live-verified: fast-track armed -> no questions, best-judgement lock-in,
  immediate render. 42/42 python, 15/15 vitest.

* checkpoint: requirements and playbook progress

* feat: harden requirements viewpoints

* docs: add ReqIF Flexo delivery handoff

* refactor(requirements): consume vendored ufo-types::mbse::requirements (M1)

kr0ki-core no longer owns the requirements semantic model — it now
re-exports ufo_types::mbse::requirements (released as ufo-types v0.15.0,
PromptExecution/ufo-types#28) as kr0ki_core::requirements. Deletes the
873-line local copy; requirements_render.rs and kr0ki-server's HTTP
routes are unchanged, since they resolve through the re-export.

Zero duplication, zero drift: the semantic model has one home now.
Verified: cargo build --workspace, clippy -D warnings, and the full
kr0ki-core/kr0ki-server test suite (148 + 44 tests) all pass against
the released tag.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CJ5M1bGQJB1VS8Epr7AGLa

* fix(d2): quote/escape labels so arbitrary text can't alter D2 structure

Addresses PR #36 review, P1 findings 1 and 2.

- crates/kr0ki-core/src/b00t_graph.rs: d2_escape_label only neutralized
  newlines, leaving D2's structural characters ({, }, :, ...) live in
  label position. A ReqIF requirement title like "normal requirement {"
  emits invalid D2 ("maps must be terminated with }") or, worse, a
  title like "{shape: circle}" gets interpreted as D2 structure instead
  of label text. Fixed at the shared helper (used by requirements_render,
  b00t_graph's own D2Emitter, and sysml_render — all three had the
  identical defect), so labels are now quoted/escaped the same way
  d2_quote already handles ids. Added adversarial-title coverage in all
  three call sites' test modules; updated the two existing tests that
  had encoded the old unquoted behavior as expected output.
- .gitmodules: vendor/assistant-ui had only `branch`, no `path`/`url`,
  so `actions/checkout` with `submodules: recursive` fails before any
  test runs — blocking every CI check regardless of this PR's content.
  Added the missing path/url (https://github.com/elasticdotventures/
  assistant-ui.git, matching the already-checked-out working tree's
  own remote and the pinned gitlink commit). Verified: `git ls-remote`
  resolves the pinned commit on that url/branch unauthenticated, and
  `git submodule init && git submodule sync` succeeds locally.

Verified: cargo build --workspace, cargo clippy --workspace -- -D
warnings, cargo test -p kr0ki-core -p kr0ki-server (150 + 44 passing).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CJ5M1bGQJB1VS8Epr7AGLa

* style: cargo fmt the adversarial-label test

CI's cargo fmt --all -- --check caught a multi-line assert_eq! rustfmt
collapses onto one line; missed locally in the prior commit since I
verified build/clippy/test there but not fmt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CJ5M1bGQJB1VS8Epr7AGLa

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
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