Compare commits
2 Commits
fix/671-pl
...
fix/533
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e99b251b68 | ||
|
|
7beae447ba |
@@ -1,7 +1,7 @@
|
||||
# NH Broadband Install Packet
|
||||
|
||||
**Packet ID:** nh-bb-20260415-113232
|
||||
**Generated:** 2026-04-15T11:32:32.781304+00:00
|
||||
**Packet ID:** nh-bb-20260417-015617
|
||||
**Generated:** 2026-04-17T01:56:17.706676+00:00
|
||||
**Status:** pending_scheduling_call
|
||||
|
||||
## Contact
|
||||
@@ -19,6 +19,26 @@
|
||||
|
||||
residential-fiber
|
||||
|
||||
## Availability Check
|
||||
|
||||
- Status: pending
|
||||
- Checked at: pending
|
||||
- Notes: Pending exact-address lookup on nhbroadband.com
|
||||
|
||||
## Pricing
|
||||
|
||||
- Monthly cost: pending live quote
|
||||
- Install fee: pending live quote
|
||||
- Quoted at: pending
|
||||
- Notes: Pending live quote from NH Broadband
|
||||
|
||||
## Appointment
|
||||
|
||||
- Scheduled for: pending
|
||||
- Window: pending
|
||||
- Confirmation number: pending
|
||||
- Installer access notes: Driveway condition note pending
|
||||
|
||||
## Call Log
|
||||
|
||||
- **2026-04-15T14:30:00Z** — no_answer
|
||||
@@ -35,3 +55,11 @@ residential-fiber
|
||||
- [ ] Post-install: run speed test (fast.com / speedtest.net)
|
||||
- [ ] Log final speeds and appointment outcome
|
||||
|
||||
## Post-Install Verification
|
||||
|
||||
- Download: pending
|
||||
- Upload: pending
|
||||
- Latency: pending
|
||||
- Tested at: pending
|
||||
- Notes: Populate after installation completes
|
||||
|
||||
|
||||
@@ -11,6 +11,31 @@ service:
|
||||
|
||||
desired_plan: residential-fiber
|
||||
|
||||
availability:
|
||||
status: pending
|
||||
checked_at: ""
|
||||
notes: "Pending exact-address lookup on nhbroadband.com"
|
||||
|
||||
pricing:
|
||||
monthly_cost_usd:
|
||||
install_fee_usd:
|
||||
quoted_at: ""
|
||||
notes: "Pending live quote from NH Broadband"
|
||||
|
||||
appointment:
|
||||
scheduled_for: ""
|
||||
window: ""
|
||||
confirmation_number: ""
|
||||
installer_access_notes: "Driveway condition note pending"
|
||||
|
||||
post_install:
|
||||
speed_test:
|
||||
download_mbps:
|
||||
upload_mbps:
|
||||
latency_ms:
|
||||
tested_at: ""
|
||||
notes: "Populate after installation completes"
|
||||
|
||||
call_log:
|
||||
- timestamp: "2026-04-15T14:30:00Z"
|
||||
outcome: no_answer
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
# GENOME.md — The Playground (Timmy_Foundation/the-playground)
|
||||
|
||||
> Codebase Genome v1.0 | Generated 2026-04-16 | Repo 11/16
|
||||
|
||||
## Project Overview
|
||||
|
||||
**The Sovereign Playground** is a browser-based creative platform for art, music, and interactive experiences. Pure Canvas + Web Audio API + vanilla JS. Zero dependencies. No login. No signup. Open the page and build something beautiful.
|
||||
|
||||
**Core principle:** A man at 3am needs something that works RIGHT NOW, with no friction, no gate, no permission.
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph "Entry Point"
|
||||
HTML[index.html] --> PLAYGROUND[playground.js]
|
||||
end
|
||||
|
||||
subgraph "Engine Layer"
|
||||
PLAYGROUND --> AUDIO[audio-engine.js]
|
||||
PLAYGROUND --> VISUAL[visual-engine.js]
|
||||
end
|
||||
|
||||
subgraph "Modes"
|
||||
PLAYGROUND --> MODES[mode-manager.js]
|
||||
MODES --> CONSTELLATION[constellation.js]
|
||||
end
|
||||
|
||||
subgraph "UI Panels"
|
||||
PLAYGROUND --> SOUND_PANEL[sound-panel.js]
|
||||
PLAYGROUND --> GALLERY_PANEL[gallery-panel.js]
|
||||
end
|
||||
|
||||
subgraph "Gallery & Export"
|
||||
PLAYGROUND --> GALLERY[gallery.js]
|
||||
PLAYGROUND --> DOWNLOAD[download.js]
|
||||
DOWNLOAD --> WAV[wav-encoder.js]
|
||||
end
|
||||
|
||||
subgraph "Utilities"
|
||||
PLAYGROUND --> EVENTS[events.js]
|
||||
PLAYGROUND --> STATE[state.js]
|
||||
PLAYGROUND --> UTILS[utils.js]
|
||||
end
|
||||
|
||||
subgraph "Styling"
|
||||
HTML --> CSS[design-system.css]
|
||||
end
|
||||
```
|
||||
|
||||
## The Three Pillars
|
||||
|
||||
| Pillar | Status | Description |
|
||||
|--------|--------|-------------|
|
||||
| CREATE | Building | Sound Studio, Visual Forge, Video Forge |
|
||||
| COLLECT | Building | Gallery — save, browse, own your creations |
|
||||
| PLAY | Building | Games Floor — interactive experiences |
|
||||
|
||||
## Key Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `index.html` | Entry point — entrance curtain + main layout |
|
||||
| `src/playground.js` | Main orchestrator — particles, entrance, mode switching |
|
||||
| `src/engine/audio-engine.js` | Web Audio API — synthesis, effects, recording |
|
||||
| `src/engine/visual-engine.js` | Canvas rendering — particles, shapes, animations |
|
||||
| `src/modes/mode-manager.js` | Mode switching — constellation, sound, visual |
|
||||
| `src/modes/constellation.js` | Constellation Maker experience |
|
||||
| `src/gallery/gallery.js` | Gallery — IndexedDB storage, browsing |
|
||||
| `src/export/download.js` | Export — zip, download, share |
|
||||
| `src/export/wav-encoder.js` | WAV encoding for audio export |
|
||||
| `src/panels/sound/sound-panel.js` | Sound Studio UI |
|
||||
| `src/panels/gallery/gallery-panel.js` | Gallery UI |
|
||||
| `src/styles/design-system.css` | Sovereign aesthetic — dark bg, gold accents |
|
||||
| `src/utils/events.js` | Event system — pub/sub |
|
||||
| `src/utils/state.js` | State management — reactive store |
|
||||
| `src/utils/utils.js` | Utility functions |
|
||||
|
||||
## Design Principles
|
||||
|
||||
1. **Local-first** — Everything runs in the browser. IndexedDB for storage.
|
||||
2. **Zero dependencies** — Pure Canvas + Web Audio API + vanilla JS.
|
||||
3. **Take it home** — Every creation can be downloaded.
|
||||
4. **Sovereign aesthetic** — Dark backgrounds. Gold accents. Plain, honest, profound.
|
||||
5. **Accessible** — Keyboard navigable. Screen reader friendly. Works on mobile.
|
||||
|
||||
## Experiences Roadmap
|
||||
|
||||
| # | Experience | Status | Description |
|
||||
|---|-----------|--------|-------------|
|
||||
| 15 | Synesthesia Engine | v0.3 | See sound, hear color |
|
||||
| 16 | Emotional Weather | v0.3 | Type feelings → sky responds |
|
||||
| 17 | Constellation Maker | v0.3 | Place stars, connect, hear night sky |
|
||||
| 18 | Breath Instrument | v0.4 | Lungs become music |
|
||||
| 19 | Dream Journal | v0.4 | Describe dream → world |
|
||||
| 20 | The Mirror | v0.4 | Camera paints your energy |
|
||||
| 21 | Sound Fossils | v0.4 | Sound → living creature |
|
||||
| 22 | Letter to Future | v0.4 | Write, seal, set date |
|
||||
| 23 | Garden Paths | v0.5 | Choose-your-own soundscape |
|
||||
| 24 | Heartbeat Sync | v0.5 | Finger on camera → world beats |
|
||||
| 25 | The Conversation | v0.5 | Two instruments create together |
|
||||
|
||||
## Milestones
|
||||
|
||||
- **v0.1** The Forge Opens — First playable
|
||||
- **v0.2** Take It Home — Download anything
|
||||
- **v0.3** The Games Floor — Synesthesia, Emotional Weather, Constellation
|
||||
- **v0.4** The Gallery Show — Breath, Dreams, Mirror, Fossils
|
||||
- **v0.5** The Video Forge — Garden, Heartbeat, Conversation
|
||||
- **v1.0** The Sovereign Playground — Full platform
|
||||
|
||||
## File Index
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `index.html` | Entry point (entrance curtain + layout) |
|
||||
| `README.md` | Project overview and philosophy |
|
||||
| `smoke-test.html` | CI smoke test |
|
||||
| `src/playground.js` | Main orchestrator (~410 LOC) |
|
||||
| `src/engine/audio-engine.js` | Web Audio synthesis |
|
||||
| `src/engine/visual-engine.js` | Canvas rendering |
|
||||
| `src/modes/constellation.js` | Constellation Maker |
|
||||
| `src/modes/mode-manager.js` | Mode switching |
|
||||
| `src/gallery/gallery.js` | Gallery system |
|
||||
| `src/export/download.js` | Export/download |
|
||||
| `src/export/wav-encoder.js` | WAV encoding |
|
||||
| `src/panels/sound/sound-panel.js` | Sound UI |
|
||||
| `src/panels/gallery/gallery-panel.js` | Gallery UI |
|
||||
| `src/styles/design-system.css` | Design system |
|
||||
| `src/utils/events.js` | Event pub/sub |
|
||||
| `src/utils/state.js` | Reactive state |
|
||||
| `src/utils/utils.js` | Utilities |
|
||||
|
||||
**Total: 17 files | Pure vanilla JS | Zero dependencies**
|
||||
|
||||
## Sovereignty Assessment
|
||||
|
||||
- **Fully local** — All computation in the browser
|
||||
- **No server** — Static files only, can be served from anywhere
|
||||
- **No accounts** — IndexedDB for local storage
|
||||
- **No tracking** — Zero analytics, zero telemetry
|
||||
- **Downloadable** — Every creation can be saved locally
|
||||
|
||||
**Verdict: Fully sovereign. Art heals. Music heals. Creation heals.**
|
||||
|
||||
---
|
||||
|
||||
*"A man who is building something is a man who is not destroying himself."*
|
||||
@@ -17,6 +17,27 @@ def load_request(path: str | Path) -> dict[str, Any]:
|
||||
data.setdefault("service", {})
|
||||
data.setdefault("call_log", [])
|
||||
data.setdefault("checklist", [])
|
||||
data.setdefault("availability", {})
|
||||
data.setdefault("pricing", {})
|
||||
data.setdefault("appointment", {})
|
||||
data.setdefault("post_install", {})
|
||||
data["availability"].setdefault("status", "pending")
|
||||
data["availability"].setdefault("checked_at", "")
|
||||
data["availability"].setdefault("notes", "")
|
||||
data["pricing"].setdefault("monthly_cost_usd", None)
|
||||
data["pricing"].setdefault("install_fee_usd", None)
|
||||
data["pricing"].setdefault("quoted_at", "")
|
||||
data["pricing"].setdefault("notes", "")
|
||||
data["appointment"].setdefault("scheduled_for", "")
|
||||
data["appointment"].setdefault("window", "")
|
||||
data["appointment"].setdefault("confirmation_number", "")
|
||||
data["appointment"].setdefault("installer_access_notes", "")
|
||||
data["post_install"].setdefault("speed_test", {})
|
||||
data["post_install"]["speed_test"].setdefault("download_mbps", None)
|
||||
data["post_install"]["speed_test"].setdefault("upload_mbps", None)
|
||||
data["post_install"]["speed_test"].setdefault("latency_ms", None)
|
||||
data["post_install"]["speed_test"].setdefault("tested_at", "")
|
||||
data["post_install"]["speed_test"].setdefault("notes", "")
|
||||
return data
|
||||
|
||||
|
||||
@@ -39,6 +60,19 @@ def build_packet(data: dict[str, Any]) -> dict[str, Any]:
|
||||
validate_request(data)
|
||||
contact = data["contact"]
|
||||
service = data["service"]
|
||||
availability = data.get("availability", {})
|
||||
pricing = data.get("pricing", {})
|
||||
appointment = data.get("appointment", {})
|
||||
post_install = data.get("post_install", {})
|
||||
speed_test = post_install.get("speed_test", {})
|
||||
|
||||
status = "pending_scheduling_call"
|
||||
if availability.get("status") == "unavailable":
|
||||
status = "blocked_unavailable"
|
||||
elif appointment.get("confirmation_number") or appointment.get("scheduled_for"):
|
||||
status = "scheduled_install"
|
||||
if speed_test.get("download_mbps") is not None:
|
||||
status = "post_install_verified"
|
||||
|
||||
return {
|
||||
"packet_id": f"nh-bb-{datetime.now(timezone.utc).strftime('%Y%m%d-%H%M%S')}",
|
||||
@@ -55,18 +89,69 @@ def build_packet(data: dict[str, Any]) -> dict[str, Any]:
|
||||
"zip": service.get("zip", ""),
|
||||
},
|
||||
"desired_plan": data.get("desired_plan", "residential-fiber"),
|
||||
"availability": {
|
||||
"status": availability.get("status", "pending"),
|
||||
"checked_at": availability.get("checked_at", ""),
|
||||
"notes": availability.get("notes", ""),
|
||||
},
|
||||
"pricing": {
|
||||
"monthly_cost_usd": pricing.get("monthly_cost_usd"),
|
||||
"install_fee_usd": pricing.get("install_fee_usd"),
|
||||
"quoted_at": pricing.get("quoted_at", ""),
|
||||
"notes": pricing.get("notes", ""),
|
||||
},
|
||||
"appointment": {
|
||||
"scheduled_for": appointment.get("scheduled_for", ""),
|
||||
"window": appointment.get("window", ""),
|
||||
"confirmation_number": appointment.get("confirmation_number", ""),
|
||||
"installer_access_notes": appointment.get("installer_access_notes", ""),
|
||||
},
|
||||
"call_log": data.get("call_log", []),
|
||||
"checklist": [
|
||||
{"item": item, "done": False} if isinstance(item, str) else item
|
||||
for item in data["checklist"]
|
||||
],
|
||||
"status": "pending_scheduling_call",
|
||||
"post_install": {
|
||||
"speed_test": {
|
||||
"download_mbps": speed_test.get("download_mbps"),
|
||||
"upload_mbps": speed_test.get("upload_mbps"),
|
||||
"latency_ms": speed_test.get("latency_ms"),
|
||||
"tested_at": speed_test.get("tested_at", ""),
|
||||
"notes": speed_test.get("notes", ""),
|
||||
}
|
||||
},
|
||||
"status": status,
|
||||
}
|
||||
|
||||
|
||||
def render_markdown(packet: dict[str, Any], data: dict[str, Any]) -> str:
|
||||
contact = packet["contact"]
|
||||
addr = packet["service_address"]
|
||||
availability = packet["availability"]
|
||||
pricing = packet["pricing"]
|
||||
appointment = packet["appointment"]
|
||||
speed_test = packet["post_install"]["speed_test"]
|
||||
|
||||
monthly_cost = pricing["monthly_cost_usd"]
|
||||
install_fee = pricing["install_fee_usd"]
|
||||
monthly_line = f"${monthly_cost:.2f}" if isinstance(monthly_cost, (int, float)) else "pending live quote"
|
||||
install_line = f"${install_fee:.2f}" if isinstance(install_fee, (int, float)) else "pending live quote"
|
||||
download_line = (
|
||||
f"{speed_test['download_mbps']} Mbps"
|
||||
if speed_test["download_mbps"] is not None else
|
||||
"pending"
|
||||
)
|
||||
upload_line = (
|
||||
f"{speed_test['upload_mbps']} Mbps"
|
||||
if speed_test["upload_mbps"] is not None else
|
||||
"pending"
|
||||
)
|
||||
latency_line = (
|
||||
f"{speed_test['latency_ms']} ms"
|
||||
if speed_test["latency_ms"] is not None else
|
||||
"pending"
|
||||
)
|
||||
|
||||
lines = [
|
||||
f"# NH Broadband Install Packet",
|
||||
"",
|
||||
@@ -89,6 +174,26 @@ def render_markdown(packet: dict[str, Any], data: dict[str, Any]) -> str:
|
||||
"",
|
||||
f"{packet['desired_plan']}",
|
||||
"",
|
||||
"## Availability Check",
|
||||
"",
|
||||
f"- Status: {availability['status']}",
|
||||
f"- Checked at: {availability['checked_at'] or 'pending'}",
|
||||
f"- Notes: {availability['notes'] or 'pending exact-address lookup'}",
|
||||
"",
|
||||
"## Pricing",
|
||||
"",
|
||||
f"- Monthly cost: {monthly_line}",
|
||||
f"- Install fee: {install_line}",
|
||||
f"- Quoted at: {pricing['quoted_at'] or 'pending'}",
|
||||
f"- Notes: {pricing['notes'] or 'pending live quote'}",
|
||||
"",
|
||||
"## Appointment",
|
||||
"",
|
||||
f"- Scheduled for: {appointment['scheduled_for'] or 'pending'}",
|
||||
f"- Window: {appointment['window'] or 'pending'}",
|
||||
f"- Confirmation number: {appointment['confirmation_number'] or 'pending'}",
|
||||
f"- Installer access notes: {appointment['installer_access_notes'] or 'pending'}",
|
||||
"",
|
||||
"## Call Log",
|
||||
"",
|
||||
]
|
||||
@@ -112,7 +217,17 @@ def render_markdown(packet: dict[str, Any], data: dict[str, Any]) -> str:
|
||||
mark = "x" if item.get("done") else " "
|
||||
lines.append(f"- [{mark}] {item['item']}")
|
||||
|
||||
lines.append("")
|
||||
lines.extend([
|
||||
"",
|
||||
"## Post-Install Verification",
|
||||
"",
|
||||
f"- Download: {download_line}",
|
||||
f"- Upload: {upload_line}",
|
||||
f"- Latency: {latency_line}",
|
||||
f"- Tested at: {speed_test['tested_at'] or 'pending'}",
|
||||
f"- Notes: {speed_test['notes'] or 'pending'}",
|
||||
"",
|
||||
])
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
|
||||
@@ -35,6 +35,11 @@ def test_load_and_build_packet() -> None:
|
||||
assert packet["status"] == "pending_scheduling_call"
|
||||
assert len(packet["checklist"]) == 8
|
||||
assert packet["checklist"][0]["done"] is False
|
||||
assert packet["availability"]["status"] == "pending"
|
||||
assert packet["pricing"]["monthly_cost_usd"] is None
|
||||
assert packet["pricing"]["install_fee_usd"] is None
|
||||
assert packet["appointment"]["confirmation_number"] == ""
|
||||
assert packet["post_install"]["speed_test"]["download_mbps"] is None
|
||||
|
||||
|
||||
def test_validate_rejects_missing_contact_name() -> None:
|
||||
@@ -86,8 +91,12 @@ def test_render_markdown_contains_key_sections() -> None:
|
||||
assert "# NH Broadband Install Packet" in md
|
||||
assert "## Contact" in md
|
||||
assert "## Service Address" in md
|
||||
assert "## Availability Check" in md
|
||||
assert "## Pricing" in md
|
||||
assert "## Appointment" in md
|
||||
assert "## Call Log" in md
|
||||
assert "## Appointment Checklist" in md
|
||||
assert "## Post-Install Verification" in md
|
||||
assert "Concord" in md
|
||||
assert "NH" in md
|
||||
|
||||
@@ -103,3 +112,16 @@ def test_example_yaml_is_valid() -> None:
|
||||
data = yaml.safe_load(Path("docs/nh-broadband-install-request.example.yaml").read_text())
|
||||
assert data["contact"]["name"] == "Timmy Operator"
|
||||
assert len(data["checklist"]) == 8
|
||||
assert data["availability"]["status"] == "pending"
|
||||
assert data["appointment"]["confirmation_number"] == ""
|
||||
|
||||
|
||||
def test_render_markdown_shows_pending_live_fields() -> None:
|
||||
data = load_request("docs/nh-broadband-install-request.example.yaml")
|
||||
packet = build_packet(data)
|
||||
md = render_markdown(packet, data)
|
||||
assert "Status: pending" in md
|
||||
assert "Monthly cost: pending live quote" in md
|
||||
assert "Install fee: pending live quote" in md
|
||||
assert "Confirmation number: pending" in md
|
||||
assert "Download: pending" in md
|
||||
|
||||
Reference in New Issue
Block a user