Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
078f3ac
feat(ahbg): add fail-closed presentation snapshot contract
erinepshovel-code Aug 31, 2026
aa94091
feat(ahbg): add accessible fail-closed presentation board
erinepshovel-code Aug 31, 2026
a940e13
style(ahbg): keep focus and selection visible
erinepshovel-code Aug 31, 2026
52a8622
docs(ahbg): add presentation board shell
erinepshovel-code Aug 31, 2026
0e55b57
feat(ahbg): add presentation-only Seed geometry helpers
erinepshovel-code Aug 31, 2026
de79e1c
test(ahbg): add presentation sample snapshot
erinepshovel-code Aug 31, 2026
3d2fdf4
feat(ahbg): add observation-to-presentation projector
erinepshovel-code Aug 31, 2026
7ab3057
docs(ahbg): document presentation-only boundary and usage
erinepshovel-code Aug 31, 2026
e1bccc2
feat(ahbg): expose presentation snapshot helpers
erinepshovel-code Aug 31, 2026
714a82d
test(ahbg): cover presentation validation and projection
erinepshovel-code Aug 31, 2026
b2f1da2
ci(ahbg): gate presentation-only surface
erinepshovel-code Aug 31, 2026
ad56d98
fix(ahbg): carry UCNS display positions and fail closed on unknown fi…
erinepshovel-code Aug 31, 2026
cadb4fa
fix(ahbg): project only declared visual fields and supplied UCNS posi…
erinepshovel-code Aug 31, 2026
90bbb2e
fix(ahbg): stop reconstructing UCNS centers in presentation geometry
erinepshovel-code Aug 31, 2026
14a3b60
fix(ahbg): render source-supplied UCNS positions and close browser va…
erinepshovel-code Aug 31, 2026
bcb3474
fix(ahbg): expose interactive tile descendants to assistive technology
erinepshovel-code Aug 31, 2026
eecfb7e
fix(ahbg): pin sample presentation to exact UCNS geometry source
erinepshovel-code Aug 31, 2026
2b5884a
meta(ahbg): declare presentation package boundary
erinepshovel-code Aug 31, 2026
5cdb242
tests(ahbg): prove UCNS geometry identity and strict presentation bou…
erinepshovel-code Aug 31, 2026
a4464f7
docs(ahbg): document UCNS-supplied presentation geometry and strict f…
erinepshovel-code Aug 31, 2026
0b4ca55
fix(ahbg): align snapshot validation contracts
erinepshovel-code Sep 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/ahbg-presentation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: ahbg-presentation

on:
pull_request:
paths:
- "ahbg/presentation/**"
- ".github/workflows/ahbg-presentation.yml"
push:
branches: [main]
paths:
- "ahbg/presentation/**"
- ".github/workflows/ahbg-presentation.yml"

permissions:
contents: read

jobs:
presentation:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Python presentation contract
run: python -m unittest discover -s ahbg/presentation/tests -p 'test*.py'
- name: Browser JavaScript syntax
run: node --check ahbg/presentation/board.js
95 changes: 95 additions & 0 deletions ahbg/presentation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# AHBG presentation

Grok-owned graphics surface. It renders validated presentation snapshots and
already-resolved motion traces. It does **not** define game mechanics or derive
UCNS geometry.

## Boundary

- Included: Seed-of-Life circle rendering, UCNS-supplied tile centerpoints,
unit markers, selection/inspection, public feed text, and visual traces of
already-resolved moves.
- Excluded: legal movement, adjacency authority, turns, War resolution,
construction, permissions, RNG, DM state, private prompt state, or agent policy.
- Snapshot standing is `ahbg.presentation.snapshot` / `not-mechanics`.
- Every snapshot carries an exact `geometry_source` identity plus each tile's
UCNS-derived `x`, `y`, and `source_slot`. The renderer only scales those
coordinates for SVG display; it never rebuilds centers from local axial rules.
- The current sample pins `The-Interdependency/ucns@1975fe70cf4e0826a8020c2da3047569e277af64`,
the canonical `libs/ucns/` identity in the stack manifest when this surface was
authored. Its `mobius_seed` module remains an explicit nonselecting UCNS
candidate; presentation consumption does not promote its standing.
- `project.py` accepts already-sanitized observation data, source-backed display
coordinates, and resolved move events. It never decides whether those moves
were legal and copies only declared browser-facing fields.
- `geometry.py` scales supplied source coordinates into display pixels only.

## Usage guidance

Validate the package:

```bash
python -m unittest discover -s ahbg/presentation/tests -p 'test*.py'
node --check ahbg/presentation/board.js
```

Serve the board locally:

```bash
cd ahbg/presentation
python -m http.server 8765 --bind 127.0.0.1
# open http://127.0.0.1:8765/board.html
```

Project a sanitized observation only after the owning adapter has attached the
UCNS-derived centers and exact source identity:

```python
from ahbg.presentation.project import snapshot_from_observation

geometry_source = {
"repository": "The-Interdependency/ucns",
"commit": "1975fe70cf4e0826a8020c2da3047569e277af64",
"module": "src/ucns/mobius_seed.py",
"schema_id": "ucns.mobius-seed-of-life",
"schema_version": "0.1.0",
"projection_id": "seed-of-life-seven-equal-circles",
"selection_effect": "none",
}
observation = {
"turn": 1,
"geometry_source": geometry_source,
"tiles": [
{"tile_id": "CENTER", "ucns_slot": "CENTER", "x": 0.0, "y": 0.0},
{"tile_id": "RING_0", "ucns_slot": "RING_0", "x": 1.0, "y": 0.0},
],
"units": [{"unit_id": "A0", "tile_id": "RING_0", "label": "A0"}],
}
move = {
"kind": "move",
"data": {"unit_id": "A0", "from_tile_id": "CENTER", "to_tile_id": "RING_0"},
}
snapshot = snapshot_from_observation(
observation,
plane_id="plane-0",
move_events=[move],
feed=[{"turn": 1, "text": "public display text only"}],
)
```

The snapshot validator is allowlist-based. Unknown root, geometry, tile, unit,
feed, or motion fields fail closed. The projector drops undeclared observation,
move-event, and feed metadata before validation, preventing a visual snapshot
from becoming a transport for private/internal fields.

The browser exposes tile inspection to pointer and keyboard input, permits
interactive descendants under an SVG `group` role, scales unit-marker spread by
occupant count, and renders the selection ring above the unit layer.

## hmmm

- whether later Flower-of-Life rings belong on this presentation surface;
- the exact live engine-to-observation adapter that attaches UCNS positions is
owned by the eventual engine integration, not by this graphics package;
- construction animation remains unavailable until an owning mechanics layer
emits an already-resolved construction event contract.
36 changes: 36 additions & 0 deletions ahbg/presentation/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# === MODULE_BUILD ===
# id: ahbg_presentation_public_boundary
# module_name: presentation
# module_kind: adapter
# summary: exposes the validated presentation snapshot and projection boundary without exporting mechanics
# owner: AHBG presentation
# public_surface: PresentationSnapshotError, load_snapshot, snapshot_from_observation, validate_snapshot
# internal_surface: none
# auth_boundary: none
# storage_boundary: none
# network_boundary: none
# user_data_boundary: none
# admin_only: false
# tests: ahbg/presentation/tests/test_presentation.py
# rollout: import explicitly from ahbg.presentation
# rollback: remove package exports with presentation package
# requires: ahbg_presentation_snapshot_contract, ahbg_presentation_observation_projector
# since: 2026-08-31
# unresolved: none
# === END MODULE_BUILD ===

"""Presentation-only AHBG graphics boundary.

Usage guidance: import only validated presentation helpers from this package;
game mechanics remain outside this namespace.
"""

from .project import snapshot_from_observation
from .snapshot import PresentationSnapshotError, load_snapshot, validate_snapshot

__all__ = [
"PresentationSnapshotError",
"load_snapshot",
"snapshot_from_observation",
"validate_snapshot",
]
45 changes: 45 additions & 0 deletions ahbg/presentation/board.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
:root {
--ink: #1b1a17;
--paper: #f4efe4;
--tile: #e6dcc8;
--tile-stroke: #6b5d44;
--selected: #c45c26;
--unit: #1f4b99;
}

html,
body {
margin: 0;
background: var(--paper);
color: var(--ink);
font: 16px/1.4 "Iowan Old Style", "Palatino Linotype", Palatino, serif;
}

main {
display: grid;
grid-template-columns: minmax(0, 1fr) 18rem;
min-height: 100vh;
}

.board-wrap { display: flex; flex-direction: column; padding: 1.5rem; }
h1, h2 { font-weight: 600; letter-spacing: 0.04em; margin: 0 0 0.75rem; }
.note { margin: 0 0 1rem; font-size: 0.95rem; }
svg { width: min(100%, 36rem); height: auto; align-self: center; }
.seed-circle { fill: none; stroke: var(--tile-stroke); stroke-width: 1.5; pointer-events: none; }
.tile-point { fill: var(--tile-stroke); stroke: var(--paper); stroke-width: 1.5; pointer-events: none; }
.tile-point.selected { fill: var(--selected); stroke: var(--selected); }
.motion-path { fill: none; stroke: var(--selected); stroke-width: 2.5; stroke-dasharray: 6 4; pointer-events: none; }
.tile-hit { fill: transparent; cursor: pointer; stroke: transparent; stroke-width: 3; }
.tile-hit:focus { outline: none; stroke: var(--selected); }
.tile-label { fill: var(--ink); font-size: 11px; pointer-events: none; text-anchor: middle; }
.unit { fill: var(--unit); stroke: var(--paper); stroke-width: 2; pointer-events: none; }
.unit-label { fill: var(--paper); font-size: 10px; pointer-events: none; text-anchor: middle; }
.selection-ring { fill: none; stroke: var(--selected); stroke-width: 3; pointer-events: none; }
.feed { background: #efe7d6; border-left: 1px solid var(--tile-stroke); padding: 1.5rem; }
.feed ol { margin: 0; padding-left: 1.2rem; }
.inspect { margin-top: 1rem; font-size: 0.95rem; }

@media (max-width: 720px) {
main { grid-template-columns: 1fr; }
.feed { border-left: 0; border-top: 1px solid var(--tile-stroke); }
}
24 changes: 24 additions & 0 deletions ahbg/presentation/board.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AHBG presentation board</title>
<link rel="stylesheet" href="board.css" />
</head>
<body>
<main>
<section class="board-wrap">
<h1>AHBG plane</h1>
<p class="note">Presentation only. Not mechanics. Tile centers are supplied by the declared UCNS source; the browser only scales them for display. Dashed traces show already-resolved motion. Click a center, or focus it and press Enter/Space, to inspect.</p>
<svg id="board" role="group" aria-label="Interactive Seed of Life presentation with inspectable tile centers and resolved unit motion traces"></svg>
</section>
<aside class="feed">
<h2>Feed</h2>
<ol id="feed-list"></ol>
<p class="inspect" id="inspect" aria-live="polite"></p>
</aside>
</main>
<script src="board.js"></script>
</body>
</html>
Loading