Skip to content

v0.9 sub-issue #7: Built-in echo Provider + end-to-end conformance harness + Quickstart docs #126

@devin-ai-integration

Description

@devin-ai-integration

v0.9 Sub-issue #7 — Built-in echo Provider + end-to-end conformance harness + docs

Part of v0.9 epic. Final sub-issue.

Pulls Stages 1–5 together: ships a built-in text_chat echo Provider so
the runtime can actually respond, adds the end-to-end conformance test
harness exercised in CI, and ships the v0.9 quickstart docs.

Spec ref

  • docs/LIFE_RUNTIME_STANDARD.md Part B §B.2.1 (LifeCapabilityProvider)
  • All sub-issues 1–6 above (this PR consumes their public surfaces).

Built-in echo Provider

runtime/providers/echo.py:

  • Implements LifeCapabilityProvider for capability_name() == "text_chat".
  • provider_name() == "echo-builtin", provider_version() == "1.0.0".
  • sandbox_class() == "built_in".
  • initialize(asset_paths, params, hard_constraints):
    • Reads params.system_prompt (if present) — used to prefix invoke().
    • Reads hard_constraints.max_response_length — clips output.
    • Stores both for invoke().
  • invoke({user_input, hosted_api_allowed, ...}):
    • Returns {text: f"You said: {user_input}"} (no LLM).
    • Truncates to max_response_length if set.
    • Ignores hosted_api_allowed (the echo Provider has no hosted mode).
  • teardown(): no-op.

This Provider is purely a reference implementation. It exists so a
fresh DLRS user can run lifectl run minimal-life-package.life and get
a meaningful response without installing any user-installed Provider.

Real Providers (TTS, video synthesis, GraphRAG-backed chat, ...) ship as
separate v0.10+ work via the DLRS Extension Architecture plugin system.

The echo Provider is auto-registered at runtime/providers/__init__.py
import time, ensuring ProviderRegistry finds it without explicit
configuration.

Update minimal-life-package fixture

examples/minimal-life-package/ already exists from v0.7 (#83) but
predates the v0.8 binding spec. Update the fixture so it has a
binding/runtime_binding.json declaring:

{
  "capabilities": ["text_chat"],
  "capability_binding": {
    "text_chat": {
      "asset_paths": [],
      "params": {
        "system_prompt": "You are a digital life instance of the test author."
      },
      "hard_constraints": {
        "max_response_length": 200
      },
      "engine_compatibility": [
        { "engine": { "name": "echo-builtin", "version_range": ">=1.0.0,<2.0.0", "strict": false } }
      ],
      "tier_floor": null
    }
  },
  "surface": {
    "ui_hints": {
      "disclosure_label": "(AI digital life instance of the test author)"
    }
  },
  "hosted_api_preference": {
    "allowed": false
  }
}

Mirror this update in the existing tools/build_life_package.py test
fixture path. Bump examples/minimal-life-package/manifest.json if
needed for v0.8 conformance.

End-to-end conformance harness

tools/test_runtime_conformance.py:

def test_e2e_minimal_life_package():
    # 1. Build the .life via existing builder
    pkg_path = build_minimal_life_package(tmpdir)
    
    # 2. Spawn lifectl run --once with a canned prompt
    proc = subprocess.run(
        ["lifectl", "run", "--once", "--no-tty",
         "--poll-interval-override", "1",
         pkg_path],
        input="Hello!\n",
        capture_output=True,
        timeout=30,
    )
    
    # 3. Assert stdout has the disclosure label + echo response
    assert proc.returncode == 0
    assert "(AI digital life instance of the test author)" in proc.stdout
    assert "You said: Hello!" in proc.stdout
    
    # 4. Assert audit log has all required events in the right order
    log = read_runtime_audit_log(pkg_path)
    assert event_order(log) == [
        "mount_attempted",
        "withdrawal_poll",          # pre-flight
        "capability_bound",         # text_chat → echo-builtin
        "mount_succeeded",
        "turn_started",
        "turn_completed",
        "withdrawal_poll",          # at least one watcher poll within 1s
        "unmount",
    ]
    
    # 5. Assert hash chain integrity
    assert validate_hash_chain(log)
    
    # 6. Assert no zombie subprocess
    assert no_zombie_children()


def test_e2e_withdrawal_revocation():
    pkg_path = build_minimal_life_package(tmpdir, withdrawal_url=mock_endpoint("/revoked"))
    # mock_endpoint returns {revoked: true} after 2 polls
    proc = subprocess.run(
        ["lifectl", "run", "--no-tty",
         "--poll-interval-override", "1",
         pkg_path],
        input="hi\nhi\nhi\nhi\nhi\n",
        capture_output=True,
        timeout=30,
    )
    assert proc.returncode == 0
    log = read_runtime_audit_log(pkg_path)
    assert any(e["event_type"] == "unmount" and e["reason"] == "withdrawal" for e in log)

5 conformance test cases total:

  1. End-to-end happy path (above).
  2. Withdrawal revocation triggers unmount within 2 polls.
  3. Expiry triggers unmount.
  4. Forbidden_use rejection round-trips.
  5. Audit chain integrity across full session.

CI integration

.github/workflows/validate.yml: replace the per-stage runtime-*
jobs (added by sub-issues 1–6) with a single consolidated
runtime-conformance job that runs python tools/test_runtime_conformance.py

  • all per-stage tests. Or keep both layers — final structure is up to
    the reviewer; either is acceptable.

Documentation

docs/LIFE_RUNTIME_QUICKSTART.md (new)

Walk-through:

  1. Install the runtime (pip install -e . from repo root for now;
    pip install dlrs-runtime from PyPI is post-v0.9).
  2. Build the example .life:
    python tools/build_life_package.py --record examples/minimal-life-package/.
  3. Run it: lifectl run --once examples/minimal-life-package/out/*.life.
  4. Inspect the runtime audit log:
    cat ~/.local/share/dlrs/mounts/<package_id>/events.jsonl.
  5. What each Stage does (link to docs/LIFE_RUNTIME_STANDARD.md Part B).

README.md + README.en.md updates

Add a "Quickstart" section pointing at the runtime quickstart doc;
update the implementation-status badge from "spec only" to "reference
runtime ✓".

docs/IMPLEMENTATION_STATUS.md + docs/GAP_ANALYSIS.md

Mark v0.9 deliverables complete + flip the runtime-completeness from 0%
to ~30% (single .life only; multi-life / .world / plugins still pending).

CHANGELOG.md

Add v0.9.0 entry summarizing the 7 sub-issues + naming the milestone
v0.9-runtime-impl.

ROADMAP.md

Update the .life Runtime Standard track row for life-runtime v0.1.1
to mark "reference impl shipped (v0.9 epic)". Add a v0.10 placeholder row
referencing the embodiment + multi-life + DLRS-EA design.

Acceptance

  • Echo Provider implements LifeCapabilityProvider correctly
  • minimal-life-package binding updated to v0.8 spec
  • All 5 e2e conformance test cases pass in CI
  • Quickstart doc written + linked from README
  • CHANGELOG / ROADMAP / IMPLEMENTATION_STATUS / GAP_ANALYSIS refreshed
  • CI runtime-conformance job green
  • Tag v0.9-runtime-impl ready for release

After merge, the v0.9 epic closes; v0.10 epic kicks off.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions