boostrap docs, tests, basic code and dev plans

This commit is contained in:
Jacob Dubin
2026-04-11 08:01:11 -05:00
parent 8f838787a0
commit a315fa66bc
13 changed files with 280 additions and 18 deletions

View File

@@ -2,5 +2,6 @@
<configuration>
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>

View File

@@ -1,12 +1,13 @@
<Solution>
<Folder Name="/docs/">
<File Path="docs/development-plan.md" />
<File Path="docs/device-bootstrap.md" />
<File Path="docs/protocol-inventory.md" />
<File Path="docs/public-site-plan.md" />
<File Path="docs/support-tiers.md" />
</Folder>
<Folder Name="/scripts/" />
<Folder Name="/scripts/boostrap/">
<Folder Name="/scripts/bootstrap/">
<File Path="scripts/bootstrap/Discover-JiboHosts.ps1" />
<File Path="scripts/bootstrap/Generate-JiboDnsOverrides.ps1" />
<File Path="scripts/bootstrap/README.md" />
@@ -28,6 +29,9 @@
<Project Path="src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Api/Jibo.Cloud.Api.csproj" />
<Project Path="src/Playground/Playground.csproj" />
</Folder>
<Folder Name="/tests/">
<Project Path="tests/Jibo.Cloud.Tests/Jibo.Cloud.Tests.csproj" />
</Folder>
<Folder Name="/src/OpenJibo.Site/">
<File Path="src/OpenJibo.Site/index.html" />
<File Path="src/OpenJibo.Site/site.css" />

View File

@@ -36,7 +36,7 @@ Jibo device -> OpenJibo cloud -> normalized runtime contracts -> capabilities an
The first supported recovery path is enthusiast-friendly, not zero-touch:
```text
QR Wi-Fi -> controlled router/DNS -> redirect legacy Jibo hosts ->
QR Wi-Fi -> inject OpenJibo region config -> set robot region ->
RCM/device patch for TLS and host acceptance -> OpenJibo cloud on Azure
```
@@ -47,6 +47,7 @@ That path is documented in [docs/device-bootstrap.md](C:/Projects/JiboExperiment
```text
OpenJibo/
docs/
development-plan.md
device-bootstrap.md
protocol-inventory.md
public-site-plan.md
@@ -78,11 +79,13 @@ OpenJibo/
- port required endpoint and WebSocket behavior from Node to .NET
- keep protocol captures and replay fixtures current
- harden device bootstrap documentation and scripts
- map more endpoints and behaviors beyond the current Node coverage
- stand up the initial `openjibo.com` information site
## Important Docs
- [Cloud overview](/src/Jibo.Cloud/README.md)
- [Development plan](/docs/development-plan.md)
- [Protocol inventory](/docs/protocol-inventory.md)
- [Support tiers](/docs/support-tiers.md)
- [Device bootstrap path](/docs/device-bootstrap.md)

View File

@@ -0,0 +1,65 @@
# Development Plan
## Summary
This document is the working implementation plan after the initial hosted-cloud scaffold.
It is intentionally broader than the current Node server. The Node server is a protocol oracle and discovery tool, not the complete map of Jibo.
## Current Scope
- stable .NET cloud scaffold
- Azure-oriented architecture and data ownership
- normalized runtime contracts for cloud-to-runtime handoff
- bootstrap documentation for region injection and targeted device patching
- starter endpoint coverage for account, notification, robot, loop, update, uploads, and core WebSocket acceptance
- starter xUnit coverage for the .NET application layer
## Next Implementation Scope
- expand HTTP `X-Amz-Target` coverage from observed traffic and fixtures
- grow WebSocket compatibility from stub acceptance into realistic turn orchestration
- replace in-memory state with Azure SQL-backed persistence
- add structured fixture replay tests
- harden region/bootstrap docs by software version
## Discovery Scope
We still need to map more than the current Node server expresses. Priority discovery areas:
- all hostnames and service prefixes observed in real startup and turn traffic
- skill launch and skill lifecycle flows
- interactivity command families beyond the current joke flow
- richer embodied speech and animation behaviors
- upload, logging, backup, and key-sharing flows
- per-version configuration differences and region handling
## Speech, Animation, And ESML
The current joke flow is only a small foothold into Jibo expressiveness.
Future work should map:
- direct speech modifiers
- animation selection and filtering
- embodied speech behaviors
- ESML and SSML subsets
- interactions between speech, visuals, and timing
Useful external references:
- [Speak-Tweak Docs](https://hri2024.jibo.media.mit.edu/Speak-Tweak-Docs)
- [ESML PDF](https://hri2024.jibo.media.mit.edu/attachments/SDK-SDK---ESML-121023-203758.pdf)
## Future Scope
- full endpoint inventory beyond the current Node mapping
- OTA-driven recovery
- paid hosted plans or donation-supported hosting
- deeper on-device bridge and OS modernization
- more capable skill/runtime integration
- possible LLM or tool-use patterns inspired by workshop-era experimentation
## MCP-Like Ideas
Recent MIT workshop materials suggest experimentation around modern AI tooling for Jibo, including an MCP-oriented idea. We should treat that as inspiration for future OpenJibo directions, not as a present dependency or supported integration.

View File

@@ -5,7 +5,7 @@
The first supported OpenJibo recovery path is:
```text
QR Wi-Fi -> controlled router/DNS -> redirect Jibo hosts ->
QR Wi-Fi -> inject OpenJibo region config -> set robot region ->
RCM/device patch -> Azure-hosted OpenJibo cloud
```
@@ -13,26 +13,44 @@ This is the path we can document, repeat, and improve.
## Why This Path Comes First
- it matches what the current Node prototype already requires
- it matches the region-driven configuration seams observed on the robot
- it keeps the hosted cloud work grounded in real device traffic
- it avoids blocking the entire revival on OTA before cloud compatibility exists
## Bootstrap Checklist
1. Connect the robot to a controlled Wi-Fi network.
2. Redirect legacy cloud hostnames to the OpenJibo environment.
3. Prevent fallback DNS from bypassing the controlled resolver.
2. Add an OpenJibo region entry to `/etc/jibo-jetstream-service.json`.
3. Set the robot `region` field in `/var/jibo/credentials.json` to the OpenJibo region.
4. Gain RCM/device access for targeted TLS or host validation changes.
5. Verify robot startup, token flow, socket flow, and first-turn behavior.
## Required Host Routing
## Region-Driven Configuration
At minimum, watch and validate:
Current findings suggest the preferred OpenJibo bootstrap path is to inject a new region configuration rather than override every hostname manually.
Confirmed paths:
- `/etc/jibo-jetstream-service.json`
Add an OpenJibo region definition that points Jibo to our cloud.
- `/var/jibo/credentials.json`
Set the robot `region` field to the injected OpenJibo region.
Observed additional region-related files worth documenting and auditing:
- `/etc/jibo-ssm/*.json`
- `/skills/jibo/Jibo/Skills/@be/be/node_modules/language-subtag-registry/data/json/registry.json`
- `/skills/jibo/Jibo/Skills/oobe-config/config.json`
These should be treated as configuration discovery targets, not yet as the authoritative complete list.
## Required Hosts
The currently relevant public hostnames for the OpenJibo cloud path are:
- `api.jibo.com`
- `api-socket.jibo.com`
- `neo-hub.jibo.com`
- `neohub.jibo.com`
## Scripted Helpers
@@ -42,7 +60,7 @@ Bootstrap helper scripts live in [scripts/bootstrap](C:/Projects/JiboExperiments
- `Generate-JiboDnsOverrides.ps1`
- `Test-OpenJiboRouting.ps1`
These are intentionally conservative helpers for discovery and verification, not destructive patch tools.
These are intentionally conservative helpers for discovery and verification, not destructive patch tools. They remain useful for controlled-network testing, even though the preferred long-term device path is region injection.
## TLS And Runtime Patching
@@ -53,6 +71,7 @@ Near-term guidance:
- record each patch location by software version
- prefer small, repeatable changes over ad hoc edits
- keep a versioned host inventory and patch checklist
- keep a versioned region-config checklist
- do not describe OTA as the primary bootstrap method until the hosted cloud is stable
## Smoke Test Goals

View File

@@ -4,6 +4,8 @@
This document tracks the currently observed cloud surface area for Jibo and helps keep the .NET port aligned with real behavior captured by the Node prototype.
It is not a claim that the current Node server covers all Jibo endpoints or behaviors. It reflects only the portions mapped so far.
Confidence levels:
- `high`: observed in code and currently represented in the .NET scaffold
@@ -17,7 +19,20 @@ Confidence levels:
| `api.jibo.com` | HTTPS API target for `X-Amz-Target` operations | high | Main request dispatch path in the Node prototype |
| `api-socket.jibo.com` | token-authenticated WebSocket path | medium | Node accepts tokenized connections and intentionally sends no greeting |
| `neo-hub.jibo.com` | listen and proactive WebSocket traffic | medium | Path-driven split between listen and `/v1/proactive` |
| `neohub.jibo.com` | likely alias/spelling variant to watch | low | Mentioned in docs; validate against real traffic |
## Region Configuration
Current robot findings suggest the preferred OpenJibo bootstrap path is to inject a new region configuration rather than treat host overrides as the only integration seam.
Confirmed or strongly observed files:
- `/etc/jibo-jetstream-service.json`
- `/var/jibo/credentials.json`
- `/etc/jibo-ssm/*.json`
- `/skills/jibo/Jibo/Skills/@be/be/node_modules/language-subtag-registry/data/json/registry.json`
- `/skills/jibo/Jibo/Skills/oobe-config/config.json`
The first two are the clearest current OpenJibo injection points. The others should remain on the audit list while endpoint and behavior mapping continues.
## HTTP Dispatch Families
@@ -65,6 +80,22 @@ The first .NET hosted milestone should fully support:
- basic listen/proactive WebSocket acceptance
- normalized turn and reply mapping for simple chat
## Known Beyond Current Node Coverage
The platform scope is broader than the endpoints currently modeled in `open-jibo-link.js`. Known areas that still need mapping include:
- broader skill launch and lifecycle behavior
- interactivity command families beyond the joke starter path
- richer animation and expression control
- ESML and embodied speech features
- additional service families and region-specific endpoint behavior
- startup and configuration differences across Jibo software variants
Useful external references for future mapping:
- [Speak-Tweak Docs](https://hri2024.jibo.media.mit.edu/Speak-Tweak-Docs)
- [ESML PDF](https://hri2024.jibo.media.mit.edu/attachments/SDK-SDK---ESML-121023-203758.pdf)
## Fixture Source
Sanitized fixtures live under [src/Jibo.Cloud/node/fixtures](C:/Projects/JiboExperiments/OpenJibo/src/Jibo.Cloud/node/fixtures) and should be expanded as real traffic is captured.

View File

@@ -3,8 +3,7 @@ param(
[string[]]$KnownHosts = @(
"api.jibo.com",
"api-socket.jibo.com",
"neo-hub.jibo.com",
"neohub.jibo.com"
"neo-hub.jibo.com"
)
)

View File

@@ -3,8 +3,7 @@ param(
[string[]]$HostNames = @(
"api.jibo.com",
"api-socket.jibo.com",
"neo-hub.jibo.com",
"neohub.jibo.com"
"neo-hub.jibo.com"
)
)

View File

@@ -20,8 +20,7 @@ public sealed class InMemoryCloudStateStore : ICloudStateStore
{
["api.jibo.com"] = "openjibo.com",
["api-socket.jibo.com"] = "openjibo.com",
["neo-hub.jibo.com"] = "openjibo.com",
["neohub.jibo.com"] = "openjibo.com"
["neo-hub.jibo.com"] = "openjibo.com"
}
};

View File

@@ -0,0 +1 @@
global using Xunit;

View File

@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Jibo.Cloud\dotnet\src\Jibo.Cloud.Application\Jibo.Cloud.Application.csproj" />
<ProjectReference Include="..\..\src\Jibo.Cloud\dotnet\src\Jibo.Cloud.Infrastructure\Jibo.Cloud.Infrastructure.csproj" />
<ProjectReference Include="..\..\src\Jibo.Runtime.Abstractions\Jibo.Runtime.Abstractions.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,64 @@
using System.Text.Json;
using Jibo.Cloud.Application.Services;
using Jibo.Cloud.Domain.Models;
using Jibo.Cloud.Infrastructure.Persistence;
namespace Jibo.Cloud.Tests.Protocol;
public sealed class JiboCloudProtocolServiceTests
{
private readonly JiboCloudProtocolService _service = new(new InMemoryCloudStateStore());
[Fact]
public async Task CreateHubToken_ReturnsTokenAndExpiry()
{
var result = await _service.DispatchAsync(new ProtocolEnvelope
{
HostName = "api.jibo.com",
Method = "POST",
ServicePrefix = "Account_20160715",
Operation = "CreateHubToken",
BodyText = "{}"
});
using var payload = JsonDocument.Parse(result.BodyText);
Assert.Equal(200, result.StatusCode);
Assert.StartsWith("hub-", payload.RootElement.GetProperty("token").GetString());
Assert.True(payload.RootElement.GetProperty("expires").GetInt64() > 0);
}
[Fact]
public async Task NewRobotToken_UsesBodyDeviceId()
{
var result = await _service.DispatchAsync(new ProtocolEnvelope
{
HostName = "api.jibo.com",
Method = "POST",
ServicePrefix = "Notification_20160715",
Operation = "NewRobotToken",
BodyText = """{"deviceId":"robot-123"}"""
});
using var payload = JsonDocument.Parse(result.BodyText);
Assert.Equal(200, result.StatusCode);
Assert.Contains("robot-123", payload.RootElement.GetProperty("token").GetString());
}
[Fact]
public async Task GetUpdateFrom_ReturnsNoOpUpdate()
{
var result = await _service.DispatchAsync(new ProtocolEnvelope
{
HostName = "api.jibo.com",
Method = "POST",
ServicePrefix = "Update_20160715",
Operation = "GetUpdateFrom",
BodyText = """{"subsystem":"robot","fromVersion":"1.0.0"}"""
});
using var payload = JsonDocument.Parse(result.BodyText);
Assert.Equal(200, result.StatusCode);
Assert.Equal("robot", payload.RootElement.GetProperty("subsystem").GetString());
Assert.True(payload.RootElement.TryGetProperty("url", out _));
}
}

View File

@@ -0,0 +1,55 @@
using System.Text.Json;
using Jibo.Cloud.Application.Services;
using Jibo.Cloud.Domain.Models;
using Jibo.Cloud.Infrastructure.Persistence;
namespace Jibo.Cloud.Tests.WebSockets;
public sealed class JiboWebSocketServiceTests
{
private readonly JiboWebSocketService _service;
public JiboWebSocketServiceTests()
{
var store = new InMemoryCloudStateStore();
_service = new JiboWebSocketService(
store,
new ProtocolToTurnContextMapper(),
new DemoConversationBroker(),
new ResponsePlanToSocketMessagesMapper());
}
[Fact]
public async Task ListenMessage_ReturnsResponseAndEos()
{
var replies = await _service.HandleMessageAsync(new WebSocketMessageEnvelope
{
HostName = "neo-hub.jibo.com",
Path = "/listen",
Kind = "neo-hub-listen",
Token = "hub-test-token",
Text = """{"type":"LISTEN","data":{"text":"hello jibo"}}"""
});
Assert.Equal(2, replies.Count);
Assert.Contains("OPENJIBO_RESPONSE", replies[0].Text);
Assert.Contains("EOS", replies[1].Text);
}
[Fact]
public async Task BinaryMessage_ReturnsAcknowledgementPayload()
{
var replies = await _service.HandleMessageAsync(new WebSocketMessageEnvelope
{
HostName = "neo-hub.jibo.com",
Path = "/listen",
Kind = "neo-hub-listen",
Token = "hub-test-token",
Binary = [1, 2, 3, 4]
});
using var payload = JsonDocument.Parse(replies[0].Text!);
Assert.Equal("OPENJIBO_AUDIO_RECEIVED", payload.RootElement.GetProperty("type").GetString());
Assert.Equal(4, payload.RootElement.GetProperty("data").GetProperty("bytes").GetInt32());
}
}