Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
`impl_rich_component!` for `Board` and `Players`, and `impl_soroban_game!` for
load/save. Public API is unchanged; all existing tests pass
- README rewritten with clean 30-line quick start and full feature documentation
- canonical example set expanded from three (`snake`, `battleship`, `guild_arena`) to ten:
`spawn_and_move` (Starter), `tic_tac_toe` (Rich components), `session_arena` (Session UX),
`hidden_hand`, `fog_explorer`, `dice_duel`, `blind_auction` (ZK circuits),
`snake` (Arcade/GameApp), `battleship` (Hidden information), `guild_arena` (Auth & recovery)
- `session_arena` example added as canonical reference for `session::SessionManager`

### Stability Notes

Expand Down
136 changes: 107 additions & 29 deletions examples/EXAMPLE_STANDARD.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,57 @@ Examples are the primary onboarding surface for external developers building gam
Every example must declare `cougr-core` using the published crate on crates.io, **not** a local path dependency.

```toml
# Correct
# Correct — external release
[dependencies]
cougr-core = "1.0"
cougr-core = "1.1"
soroban-sdk = "25.1.0"

# Wrong — breaks for external users
# Wrong for published examples — breaks for external users
[dependencies]
cougr-core = { path = "../../" }

```

Path dependencies silently work inside the monorepo but fail for any developer who installs the example independently. The published crate is the contract.

### 1.1 Path Dependencies in Monorepo Development

Some canonical examples depend on APIs that have not yet been published to crates.io (e.g. `circuits`, `session`, `SorobanGame`). These examples **must** use path dependencies during monorepo development but **must** switch to published versions before any release tag is cut.

**When path dependencies are permitted:**

* The example exercises an API that exists only in the workspace copy of `cougr-core` (e.g. `cougr_core::circuits::*`, `cougr_core::session::*`, `cougr_core::test::*`).
* The example is under active development inside the monorepo and no crate version on crates.io yet includes the required API.

**When path dependencies must be replaced:**

* Before cutting a release tag (including release candidates), every example's `Cargo.toml` must be updated to reference the published crate version.
* If the required API is available in a published version, the path dependency must be replaced immediately, even outside a release cycle.

**How to mark a path-dependency example:**

Add a comment above the dependency line explaining the exception:

```toml
# path dep — pending cougr-core 1.x publication of circuits::*
cougr-core = { path = "../../" }

```

CI must fail if any example still carries a path dependency at release-tag time.

**Current examples using path dependencies (as of 1.1.0):**

| Example | Reason for path dependency |
| --- | --- |
| `spawn_and_move` | Exercises `SorobanGame` / `impl_soroban_game!` |
| `tic_tac_toe` | Exercises `impl_soroban_game!` and `impl_rich_component!` |
| `session_arena` | Exercises `session::SessionManager` (Beta) |
| `hidden_hand` | Exercises `circuits::hidden_cards` (Experimental) |
| `fog_explorer` | Exercises `circuits::fog_of_war` (Experimental) |
| `dice_duel` | Exercises `circuits::fair_dice` (Experimental) |
| `blind_auction` | Exercises `circuits::sealed_bid` (Experimental) |

---

## 2. Required Validation Commands
Expand All @@ -34,6 +73,7 @@ Every example must pass both of the following commands without errors or warning
```bash
cargo test
stellar contract build

```

`cargo test` validates the game logic in the Soroban test environment. `stellar contract build` validates that the contract compiles to a valid WASM artifact using the Stellar toolchain. A Rust crate that compiles with `cargo build` but fails `stellar contract build` is not a valid Soroban contract.
Expand All @@ -56,12 +96,13 @@ examples/<name>/
├── lib.rs # Contract entrypoints, #[contract] impl, GameApp wiring
├── components.rs # Cougr components (impl_component! types)
└── systems.rs # Game systems registered with GameApp

```

### Extended layout (use when applicable)

| File | When to add |
|---|---|
| --- | --- |
| `types.rs` | Domain enums or structs shared across modules but not Cougr components |
| `auth.rs` | Session key setup, `CougrAccount` wiring, multi-device logic |
| `privacy.rs` | Commit-reveal flows, Merkle proof helpers, hidden-state management |
Expand All @@ -76,7 +117,7 @@ Do not add files that are not used. Do not collapse `components.rs` and `systems
Every example must have a `README.md` that covers all of the following sections. Keep each section concise; depth belongs in inline code comments, not in the README.

| Section | Required content |
|---|---|
| --- | --- |
| **Purpose and pattern** | One paragraph: what game mechanic does this demonstrate and which Cougr pattern does it showcase? |
| **Public contract API** | A table or list of every `#[contractimpl]` function: name, parameters, return type, one-line description |
| **Architecture overview** | How systems, components, and the `GameApp` tick interact. A short prose description or ASCII diagram |
Expand All @@ -95,7 +136,7 @@ Avoid embedding hardcoded contract IDs, testnet addresses, or deployment results
Each example must have a test module (typically `src/lib.rs` inline tests or `src/test.rs`) that covers the following categories:

| Category | What to test |
|---|---|
| --- | --- |
| **Initialization** | Calling the init function produces valid starting state |
| **Happy-path gameplay** | One full game round proceeds without errors |
| **Invalid actions** | Illegal moves, out-of-turn actions, or bad input return the expected error |
Expand All @@ -108,10 +149,10 @@ Tests must use the `soroban-sdk` `testutils` feature and `Env::default()`. Do no

## 6. Repository Hygiene

- Do not commit `target/` directories. Each example's `.gitignore` (or the root `.gitignore`) must exclude them.
- Do not commit `.wasm` artifacts, `*.wasm`, or build output.
- `Cargo.lock` should be committed for examples (they are end-user applications, not libraries).
- Keep `Cargo.toml` minimal: only direct dependencies, no unused features, no wildcard version specifiers.
* Do not commit `target/` directories. Each example's `.gitignore` (or the root `.gitignore`) must exclude them.
* Do not commit `.wasm` artifacts, `*.wasm`, or build output.
* `Cargo.lock` should be committed for examples (they are end-user applications, not libraries).
* Keep `Cargo.toml` minimal: only direct dependencies, no unused features, no wildcard version specifiers.

---

Expand All @@ -121,13 +162,20 @@ Tests must use the `soroban-sdk` `testutils` feature and `Env::default()`. Do no

A canonical example is a maintained reference architecture. It is held to the full standard in this document and is expected to stay current as `cougr-core` evolves. Canonical examples are the ones new contributors should read first.

Current canonical examples:

| Example | Pattern demonstrated |
|---|---|
| `snake` | Arcade loop, `GameApp` tick model, basic ECS |
| `battleship` | Hidden-information, commit-reveal, `privacy::stable` Merkle primitives |
| `guild_arena` | Account abstraction, social recovery, multi-device authorization |
Current canonical examples (aligned with the 1.1.0 release):

| Example | Category | Pattern demonstrated |
| --- | --- | --- |
| `spawn_and_move` | Starter | Complete idiomatic Cougr pattern: `SorobanGame` + `impl_component_observed!` + typed ECS |
| `tic_tac_toe` | Rich components | Turn-based game with `impl_rich_component!` for `Address` and `Vec` fields |
| `session_arena` | Session UX | `session::SessionManager`, session lifecycle, and multi-round state (Beta) |
| `hidden_hand` | ZK circuits | `circuits::hidden_cards` — hidden-card ZK proof flow (Experimental) |
| `fog_explorer` | ZK circuits | `circuits::fog_of_war` — fog-of-war exploration with Merkle proofs (Experimental) |
| `dice_duel` | ZK circuits | `circuits::fair_dice` — fair dice roll with on-chain verification (Experimental) |
| `blind_auction` | ZK circuits | `circuits::sealed_bid` — sealed-bid auction with commit-reveal ZK (Experimental) |
| `snake` | Arcade (GameApp) | Arcade loop, `GameApp` tick model, basic ECS |
| `battleship` | Hidden information | Commit-reveal and selective state disclosure using `privacy::stable` Merkle primitives |
| `guild_arena` | Authentication & recovery | Account abstraction, social recovery, multi-device authorization |

### Transitional examples

Expand All @@ -136,6 +184,7 @@ A transitional example is one that was written before the current standard or th
```markdown
> **Transitional example**: This example uses an older Cougr pattern and is preserved
> for compatibility reference. For the current recommended approach, see `snake`.

```

Transitional examples are still expected to pass `cargo test` and `stellar contract build`. They are not required to match the module structure or README depth of canonical examples, but they must not mislead readers into thinking the older pattern is preferred.
Expand All @@ -146,19 +195,47 @@ Transitional examples are still expected to pass `cargo test` and `stellar contr

Use the following table to decide which Cougr APIs an example should use and document.

| API | Use when |
|---|---|
| `GameApp` | Any example with more than one system or stage |
| `ScheduleStage` | Systems must run in a defined order within a tick |
| `SimpleWorld` | The example stores and queries entities with multiple components |
| `SimpleQueryBuilder` | The example scans entities by component type (more than one entity type) |
| `auth` (Beta) | The example demonstrates session keys, multi-device flows, or account recovery |
| `privacy::stable` | The example demonstrates commit-reveal, Merkle proofs, or selective disclosure |
| `privacy::experimental` | The example demonstrates Groth16 proof submission or BN254/BLS12-381 operations |
| `ops` standards | The example needs pausability, access control, or ownership transfer |
| API | Use when | Stability |
| --- | --- | --- |
| `SorobanGame` trait | Any example that loads/saves `SimpleWorld` to Soroban storage; implement once with `impl_soroban_game!` | Stable |
| `impl_soroban_game!` macro | Wiring `SorobanGame` to a `#[contract]` struct; replaces manual `load_world` / `save_world` boilerplate | Stable |
| `GameApp` | Any example with more than one system or stage | Stable |
| `ScheduleStage` | Systems must run in a defined order within a tick | Stable |
| `SimpleWorld` | The example stores and queries entities with multiple components | Stable |
| `SimpleQueryBuilder` | The example scans entities by component type (more than one entity type) | Stable |
| `impl_rich_component!` | A component contains `Address` or `Vec` fields that need Soroban-native storage | Stable |
| `session::SessionManager` | The example manages multi-round player sessions, timeouts, or session-key lifecycle | Beta |
| `circuits::hidden_cards` | The example demonstrates hidden-card ZK proof flows | Experimental |
| `circuits::fog_of_war` | The example demonstrates fog-of-war exploration with Merkle proof verification | Experimental |
| `circuits::fair_dice` | The example demonstrates fair dice roll with on-chain Groth16 verification | Experimental |
| `circuits::sealed_bid` | The example demonstrates sealed-bid auctions with commit-reveal ZK proofs | Experimental |
| `test::GameHarness` | Writing integration tests that exercise full game rounds in a sandboxed Soroban environment; pair with `Scenario` and `ReplayLog` | Experimental |
| `auth` (Beta) | The example demonstrates session keys, multi-device flows, or account recovery | Beta |
| `privacy::stable` | The example demonstrates commit-reveal, Merkle proofs, or selective disclosure | Stable |
| `privacy::experimental` | The example demonstrates Groth16 proof submission or BN254/BLS12-381 operations | Experimental |
| `ops` standards | The example needs pausability, access control, or ownership transfer | Stable |

When an API is used, the README must explain **why** that API was chosen, not just that it was used.

### API–Example Cross Reference

The following table maps each canonical example to its primary Cougr APIs:

| Example | Primary APIs |
| --- | --- |
| `spawn_and_move` | `SorobanGame`, `impl_soroban_game!`, `impl_component_observed!`, `SimpleWorld`, `SimpleQueryBuilder` |
| `tic_tac_toe` | `SorobanGame`, `impl_soroban_game!`, `impl_rich_component!`, `GameApp` |
| `session_arena` | `SorobanGame`, `session::SessionManager`, `GameApp` |
| `hidden_hand` | `SorobanGame`, `circuits::hidden_cards`, `privacy::experimental` |
| `fog_explorer` | `SorobanGame`, `circuits::fog_of_war`, `privacy::stable` |
| `dice_duel` | `SorobanGame`, `circuits::fair_dice`, `privacy::experimental` |
| `blind_auction` | `SorobanGame`, `circuits::sealed_bid`, `privacy::experimental` |
| `snake` | `GameApp`, `ScheduleStage`, `SimpleWorld`, `SimpleQueryBuilder` |
| `battleship` | `privacy::stable`, `GameApp`, `SimpleWorld` |
| `guild_arena` | `auth`, `ops::Ownable`, `ops::RecoveryGuard`, `GameApp` |

> **Note:** All `circuits::*` functions return a `GameCircuitSpec` and are currently considered **Experimental** (matching the `CHANGELOG.md`).

---

## Quality Checklist
Expand All @@ -169,7 +246,7 @@ Copy this checklist into a follow-up cleanup issue for each example:
## Example quality checklist — `<example-name>`

### Dependencies
- [ ] Uses published `cougr-core` version, not a path dependency
- [ ] Uses published `cougr-core` version, not a path dependency — **or** carries an annotated path dependency exception per §1.1

### Build validation
- [ ] `cargo test` passes
Expand Down Expand Up @@ -208,5 +285,6 @@ Copy this checklist into a follow-up cleanup issue for each example:

### Classification
- [ ] Marked as canonical or transitional in the README
- [ ] If canonical: category matches one listed in §7 (Starter, Rich components, Session UX, ZK circuits, Arcade, Hidden information, Authentication & recovery)
- [ ] If transitional: banner note present pointing to preferred alternative
```

Loading