Apply post-M1 corrections to the planning package
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# Adventure Storyteller — Production Build Milestones
|
# Adventure Storyteller — Production Build Milestones
|
||||||
|
|
||||||
**Status:** Planning-ready; implementation not yet authorized
|
**Status:** In implementation. M1 complete (2026-09-02); M2 next
|
||||||
**Base:** AI-DnD `d72f7c1bda0f34fccd84afb7a25c34eb01c901de`
|
**Base:** AI-DnD `d72f7c1bda0f34fccd84afb7a25c34eb01c901de`
|
||||||
|
|
||||||
## 1. Purpose
|
## 1. Purpose
|
||||||
@@ -63,6 +63,15 @@ Create the production fork from the pinned AI-DnD commit and make ordinary local
|
|||||||
- verify explicitly configured trusted-LAN Ollama story generation while the storyteller UI/API remains loopback-bound,
|
- verify explicitly configured trusted-LAN Ollama story generation while the storyteller UI/API remains loopback-bound,
|
||||||
- establish baseline regression/test report.
|
- establish baseline regression/test report.
|
||||||
|
|
||||||
|
**Added during implementation:** outbound TLS trust. A trusted-LAN Ollama may be
|
||||||
|
served over HTTPS with a privately issued certificate, which the inherited HTTP
|
||||||
|
client refused because it verified against a bundled public-CA list only. M1
|
||||||
|
made outbound HTTPS verify against the operating system's CA store as well,
|
||||||
|
with verification and hostname checking fully intact and no bypass option
|
||||||
|
(ADR 002; `backend/app/tlstrust.py`). This was not in the scope list above but
|
||||||
|
was on M1's critical path: without it the trusted-LAN Definition of Done below
|
||||||
|
is unreachable against a realistic host.
|
||||||
|
|
||||||
## Explicit Non-Scope
|
## Explicit Non-Scope
|
||||||
|
|
||||||
- no history rewrite yet,
|
- no history rewrite yet,
|
||||||
@@ -86,6 +95,22 @@ Must demonstrate:
|
|||||||
|
|
||||||
A clean production build can start, open the browser UI, generate and persist story turns through either same-host Ollama or an explicitly configured trusted-LAN Ollama host, restart, and resume with outbound Internet blocked. The storyteller UI/API remains loopback-bound by default.
|
A clean production build can start, open the browser UI, generate and persist story turns through either same-host Ollama or an explicitly configured trusted-LAN Ollama host, restart, and resume with outbound Internet blocked. The storyteller UI/API remains loopback-bound by default.
|
||||||
|
|
||||||
|
## Status: COMPLETE
|
||||||
|
|
||||||
|
Accepted 2026-09-02. Evidence: `planning/reports/M1-BASELINE-REPORT.md` (run
|
||||||
|
logs and packet captures) and `planning/reports/M1-IMPLEMENTATION-REPORT.md`
|
||||||
|
(review report). A01-A06, H01-H03 and H11 all pass on runtime evidence; 648
|
||||||
|
backend tests pass, including with no route to the Internet.
|
||||||
|
|
||||||
|
**Capabilities M1 delivered, which later milestones inherit rather than build:**
|
||||||
|
|
||||||
|
- offline first turn — the tokenizer table is vendored and digest-checked,
|
||||||
|
- no remote runtime assets — fonts self-hosted, CSP names no remote origin,
|
||||||
|
- loopback-bound storyteller in every run path, including the published Docker port,
|
||||||
|
- **working trusted-LAN inference, plain HTTP and HTTPS with a private CA**,
|
||||||
|
demonstrated against a second physical machine,
|
||||||
|
- a reproducible environment (`backend/requirements.lock`) and an offline-capable test suite.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# M2 — Remove Hosted, Cloud, Scripting, and Unneeded Deployment Surface
|
# M2 — Remove Hosted, Cloud, Scripting, and Unneeded Deployment Surface
|
||||||
@@ -111,7 +136,15 @@ Remove or isolate as appropriate:
|
|||||||
|
|
||||||
Add:
|
Add:
|
||||||
|
|
||||||
- explicit Ollama endpoint policy: same-host loopback default plus user-configured trusted-LAN inference,
|
- explicit Ollama endpoint policy. **Trusted-LAN inference already works as of
|
||||||
|
M1** — same-host loopback default, user-configured LAN endpoint, HTTP or
|
||||||
|
HTTPS with a privately issued certificate, verified against the machine's CA
|
||||||
|
store. M2's job is not to invent that capability but to **formalize and
|
||||||
|
narrow** it: decide and enforce what an endpoint may be in normal v1
|
||||||
|
configuration, reject or remove what it may not, and keep the endpoint's
|
||||||
|
configuration from affecting the storyteller's own loopback bind. Do not
|
||||||
|
regress the TLS behavior while narrowing the surface — the shared
|
||||||
|
verification context must follow any client the removal work rewrites,
|
||||||
- clear local-model connection diagnostics,
|
- clear local-model connection diagnostics,
|
||||||
- migration/test instrumentation replacements for any tests that depended on JS hooks or removed hosted paths.
|
- migration/test instrumentation replacements for any tests that depended on JS hooks or removed hosted paths.
|
||||||
|
|
||||||
@@ -126,7 +159,7 @@ Add:
|
|||||||
- local story play still works,
|
- local story play still works,
|
||||||
- existing tree/retry/memory/context behavior remains intact,
|
- existing tree/retry/memory/context behavior remains intact,
|
||||||
- application requires no cloud API keys,
|
- application requires no cloud API keys,
|
||||||
- approved trusted-LAN Ollama endpoints work while arbitrary public/Internet provider endpoints are rejected or absent from normal production configuration,
|
- approved trusted-LAN Ollama endpoints work — including an HTTPS endpoint with a privately issued certificate, per A06 — while arbitrary public/Internet provider endpoints are rejected or absent from normal production configuration,
|
||||||
- removed provider/auth/analytics/scripting paths are no longer reachable from normal production configuration.
|
- removed provider/auth/analytics/scripting paths are no longer reachable from normal production configuration.
|
||||||
|
|
||||||
## Definition of Done
|
## Definition of Done
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# ADR 002 — Ollama Is the v1 Model Backend
|
# ADR 002 — Ollama Is the v1 Model Backend
|
||||||
|
|
||||||
**Status:** Accepted
|
**Status:** Accepted; transport/TLS consequence added after M1
|
||||||
|
|
||||||
## Decision
|
## Decision
|
||||||
|
|
||||||
@@ -30,3 +30,31 @@ Ollama is already available locally, provides a simple local API, supports both
|
|||||||
- LAN inference does not imply LAN exposure of the storyteller UI/API; the storyteller should still bind to loopback by default,
|
- LAN inference does not imply LAN exposure of the storyteller UI/API; the storyteller should still bind to loopback by default,
|
||||||
- arbitrary public Internet/cloud model endpoints remain outside normal v1 configuration,
|
- arbitrary public Internet/cloud model endpoints remain outside normal v1 configuration,
|
||||||
- future backend abstraction may be added, but v1 should not be delayed to support it.
|
- future backend abstraction may be added, but v1 should not be delayed to support it.
|
||||||
|
|
||||||
|
## Transport for a Trusted-LAN Endpoint
|
||||||
|
|
||||||
|
Added after M1. Same-host Ollama speaks plain HTTP over loopback, and it was
|
||||||
|
assumed a LAN endpoint would look the same. It does not have to.
|
||||||
|
|
||||||
|
A trusted-LAN Ollama may be served over **HTTPS with a certificate issued by a
|
||||||
|
private or local CA** rather than a public one — a self-hosted server that
|
||||||
|
terminates TLS for everything it exposes is the ordinary case, not an exotic
|
||||||
|
one, and it may offer no cleartext port at all. A v1 client that trusts only a
|
||||||
|
bundled public-CA list cannot talk to such a host, while `curl` and the user's
|
||||||
|
browser on the same machine can.
|
||||||
|
|
||||||
|
Therefore:
|
||||||
|
|
||||||
|
- production clients must verify against the **operating system's trusted CA
|
||||||
|
store** in addition to any bundled certificate list, so a CA the user has
|
||||||
|
installed on their own machine is honoured by this application too;
|
||||||
|
- certificate **and hostname** verification remain fully enabled;
|
||||||
|
- there must be **no "ignore TLS errors" / "insecure" option**, in the UI,
|
||||||
|
in configuration, or as an environment variable. A LAN endpoint the machine
|
||||||
|
does not trust is a configuration problem to fix at the OS level, not a check
|
||||||
|
to switch off;
|
||||||
|
- the endpoint URL must therefore accept `https://` on any port, not only
|
||||||
|
`http://…:11434`.
|
||||||
|
|
||||||
|
M1 implemented this (`backend/app/tlstrust.py`); see
|
||||||
|
`planning/reports/M1-IMPLEMENTATION-REPORT.md` §G.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# ADR 004 — Local-Only Production Default
|
# ADR 004 — Local-Only Production Default
|
||||||
|
|
||||||
**Status:** Accepted; Phase 0B hardening requirements identified
|
**Status:** Accepted; Phase 0B hardening requirements identified; testing consequence strengthened after M1
|
||||||
|
|
||||||
## Decision
|
## Decision
|
||||||
|
|
||||||
@@ -31,6 +31,27 @@ The selected AI-DnD base does **not** satisfy this requirement unchanged:
|
|||||||
|
|
||||||
These are bounded production-hardening tasks rather than reasons to reject the fork.
|
These are bounded production-hardening tasks rather than reasons to reject the fork.
|
||||||
|
|
||||||
|
## Testing Consequence
|
||||||
|
|
||||||
|
Strengthened after M1, which confirmed the failure mode this rule exists to catch.
|
||||||
|
|
||||||
|
**Offline behavior must be tested with a fresh cache/data state on a machine
|
||||||
|
with no route to the Internet.** Both inherited violations above were *first-use*
|
||||||
|
downloads: `tiktoken` caches its encoding to a temp directory, and the browser
|
||||||
|
caches Google's fonts. On any machine that had been online once, both were
|
||||||
|
invisible — the application appeared to work offline while depending on an
|
||||||
|
artifact an earlier online run had left behind. Neither was findable by static
|
||||||
|
analysis; each took an actually isolated run to surface.
|
||||||
|
|
||||||
|
Therefore an offline claim is only evidence when the test:
|
||||||
|
|
||||||
|
- runs on a network with **no route out and no external DNS**, verified before
|
||||||
|
the test rather than assumed,
|
||||||
|
- starts from a **fresh application data directory and a fresh cache**, so
|
||||||
|
nothing warmed by a previous run is available,
|
||||||
|
- exercises the **first** story turn, which is when a first-use download fires,
|
||||||
|
- observes actual network destinations rather than only the absence of an error.
|
||||||
|
|
||||||
## Consequences
|
## Consequences
|
||||||
|
|
||||||
The production application must avoid or remove:
|
The production application must avoid or remove:
|
||||||
@@ -48,4 +69,11 @@ The production application must avoid or remove:
|
|||||||
|
|
||||||
Production packaging must contain all runtime assets required for ordinary story use after the user has installed the intended local Ollama models.
|
Production packaging must contain all runtime assets required for ordinary story use after the user has installed the intended local Ollama models.
|
||||||
|
|
||||||
|
Vendored runtime artifacts should be **integrity-verifiable where practical**: a
|
||||||
|
recorded source and a digest the application checks when it loads them, rather
|
||||||
|
than an opaque blob nobody can re-derive. A substituted or truncated artifact
|
||||||
|
should then fail loudly instead of silently changing behavior — a corrupted
|
||||||
|
tokenizer table, for instance, would quietly change every token count the
|
||||||
|
context budget is computed from.
|
||||||
|
|
||||||
The storyteller application should bind to loopback by default. Ollama should default to same-host loopback but may be explicitly configured to an approved trusted-LAN endpoint for v1. This LAN inference path does not authorize LAN exposure of the storyteller UI/API. Arbitrary public/Internet inference endpoints remain prohibited in normal v1 configuration.
|
The storyteller application should bind to loopback by default. Ollama should default to same-host loopback but may be explicitly configured to an approved trusted-LAN endpoint for v1. This LAN inference path does not authorize LAN exposure of the storyteller UI/API. Arbitrary public/Internet inference endpoints remain prohibited in normal v1 configuration.
|
||||||
|
|||||||
+29
-8
@@ -1,7 +1,7 @@
|
|||||||
# Adventure Storyteller Planning Package
|
# Adventure Storyteller Planning Package
|
||||||
|
|
||||||
**Status:** Phase 0 complete; architecture selected; planning revision ready for review.
|
**Status:** Phase 0 complete; architecture selected; **Milestone M1 implemented and accepted (2026-09-02)**.
|
||||||
**Production coding:** Not yet authorized. Review this package before preparing the first implementation prompt.
|
**Production coding:** Underway, milestone by milestone. M1 is done; M2 is the next milestone to brief.
|
||||||
|
|
||||||
This package contains the current product requirements, final Phase 0 architecture decisions, detailed subsystem designs, acceptance tests, research evidence, and the production milestone plan for the local-only interactive-story project.
|
This package contains the current product requirements, final Phase 0 architecture decisions, detailed subsystem designs, acceptance tests, research evidence, and the production milestone plan for the local-only interactive-story project.
|
||||||
|
|
||||||
@@ -153,14 +153,17 @@ Phase 0 research and spikes COMPLETE
|
|||||||
Architecture/fork decision COMPLETE
|
Architecture/fork decision COMPLETE
|
||||||
|
|
|
|
||||||
v
|
v
|
||||||
Planning package revision CURRENT REVIEW
|
Planning package revision COMPLETE
|
||||||
|
|
|
|
||||||
v
|
v
|
||||||
Approve planning package
|
Approve planning package COMPLETE
|
||||||
|
|
|
|
||||||
v
|
v
|
||||||
Prepare one implementation prompt
|
Milestone M1 COMPLETE (2026-09-02)
|
||||||
for Production Milestone 1
|
fork + offline baseline see planning/reports/M1-*.md
|
||||||
|
|
|
||||||
|
v
|
||||||
|
Milestone M2 NEXT — brief not yet prepared
|
||||||
|
|
|
|
||||||
v
|
v
|
||||||
Implement and review milestone-by-milestone
|
Implement and review milestone-by-milestone
|
||||||
@@ -168,6 +171,24 @@ Implement and review milestone-by-milestone
|
|||||||
|
|
||||||
## Stop Rule
|
## Stop Rule
|
||||||
|
|
||||||
**Do not begin production coding from this package yet.**
|
**One milestone at a time. Do not begin a milestone before its brief exists.**
|
||||||
|
|
||||||
The current action is to review the planning changes. No replacement Codex prompt has been prepared in this revision.
|
M1 is complete and accepted; its evidence is in `reports/M1-BASELINE-REPORT.md`
|
||||||
|
and `reports/M1-IMPLEMENTATION-REPORT.md`. **No M2 brief has been prepared.**
|
||||||
|
The current action is to review the post-M1 planning corrections below before
|
||||||
|
writing one.
|
||||||
|
|
||||||
|
### Post-M1 corrections applied (2026-09-02)
|
||||||
|
|
||||||
|
Implementation evidence contradicted or under-specified six places in this
|
||||||
|
package, and a seventh was added on review. All seven are now corrected:
|
||||||
|
|
||||||
|
| Document | Correction |
|
||||||
|
| --- | --- |
|
||||||
|
| `DECISIONS/002-ollama-only-v1.md` | New section: a trusted-LAN Ollama may be HTTPS with a private CA; verify against the OS trust store; full certificate and hostname checking; no bypass option. |
|
||||||
|
| `DECISIONS/004-local-only-production.md` | New *Testing Consequence*: offline tests need a fresh cache and no route out. Vendored runtime artifacts should be integrity-verifiable. |
|
||||||
|
| `V1-ACCEPTANCE-TESTS.md` A05 | Pass conditions reworded around *accepted* history; explicit note that the user's submitted text is deliberately retained. |
|
||||||
|
| `V1-ACCEPTANCE-TESTS.md` A06 | Now requires a real second machine and an HTTPS endpoint with a locally issued certificate; a plain-HTTP LAN test is no longer sufficient evidence. |
|
||||||
|
| `V1-ACCEPTANCE-TESTS.md` §3 | Record CPU/GPU/RAM: cold model load on a CPU-only host exceeded the inherited 120 s timeout. |
|
||||||
|
| `BUILD-MILESTONES.md` | M1 marked COMPLETE with the capabilities it delivered; M2's endpoint-policy line reframed from inventing trusted-LAN support to narrowing it. |
|
||||||
|
| `TECHNICAL-DESIGN.md` §5 | Runtime boundary restated: the storyteller is loopback-only, inference may be same-host *or* trusted-LAN, and the two are independent. Adds the TLS/private-CA rule. |
|
||||||
|
|||||||
@@ -783,6 +783,26 @@ LAN access to the **storyteller browser UI/API** is different and remains a futu
|
|||||||
|
|
||||||
Do not accidentally inherit storyteller LAN exposure because a candidate project binds to all interfaces.
|
Do not accidentally inherit storyteller LAN exposure because a candidate project binds to all interfaces.
|
||||||
|
|
||||||
|
### Two different TLS questions — do not conflate them
|
||||||
|
|
||||||
|
Clarified after M1, which implemented one of these and not the other.
|
||||||
|
|
||||||
|
**Inbound TLS — serving the storyteller over HTTPS.** Deferred, and still
|
||||||
|
deferred. It only becomes a question if storyteller LAN access is ever added.
|
||||||
|
This is what "local certificate support" refers to in the deferred list further
|
||||||
|
down.
|
||||||
|
|
||||||
|
**Outbound TLS — verifying the certificate of a trusted-LAN inference host.**
|
||||||
|
**Implemented in M1 and required for v1.** A LAN Ollama is often served over
|
||||||
|
HTTPS with a privately issued certificate, so the storyteller must verify
|
||||||
|
against the machine's own CA store as well as any bundled list, with
|
||||||
|
certificate and hostname checking fully enabled and no bypass option
|
||||||
|
(ADR 002; `TECHNICAL-DESIGN.md` §5).
|
||||||
|
|
||||||
|
The storyteller remaining loopback-bound is unaffected by either. Outbound
|
||||||
|
verification is about who the storyteller is willing to *talk to*; inbound TLS
|
||||||
|
would be about who may talk to *it*.
|
||||||
|
|
||||||
## 54. Tailscale / VPN Access
|
## 54. Tailscale / VPN Access
|
||||||
|
|
||||||
Treat remote access to the storyteller UI/API like storyteller LAN access.
|
Treat remote access to the storyteller UI/API like storyteller LAN access.
|
||||||
@@ -1167,7 +1187,9 @@ Potential later improvements:
|
|||||||
- signed release builds,
|
- signed release builds,
|
||||||
- dependency SBOM,
|
- dependency SBOM,
|
||||||
- LAN authentication,
|
- LAN authentication,
|
||||||
- local certificate support,
|
- local certificate support **for serving the storyteller over HTTPS** — note
|
||||||
|
that *outbound* verification of a trusted-LAN inference host's certificate is
|
||||||
|
a separate matter, is required for v1, and was implemented in M1 (see §53),
|
||||||
- optional AppArmor/container confinement.
|
- optional AppArmor/container confinement.
|
||||||
|
|
||||||
These are not required for initial v1 unless Phase 0B reveals a specific need.
|
These are not required for initial v1 unless Phase 0B reveals a specific need.
|
||||||
|
|||||||
@@ -132,19 +132,59 @@ Accepted Story / Scene State
|
|||||||
|
|
||||||
`Local-only` means user-controlled local infrastructure with no required Internet/cloud dependency; it does not require every process to share one host.
|
`Local-only` means user-controlled local infrastructure with no required Internet/cloud dependency; it does not require every process to share one host.
|
||||||
|
|
||||||
Default same-host runtime path:
|
The architecture has **two boundaries, and they are not the same boundary**. The
|
||||||
|
storyteller is loopback-only, always. Inference may be same-host or on a
|
||||||
|
specifically configured trusted-LAN machine. Wording that describes Ollama as
|
||||||
|
simply "loopback/local" collapses the two and understates the intended
|
||||||
|
deployment:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
Browser -> local FastAPI application -> 127.0.0.1 Ollama
|
Browser ──loopback──> storyteller (FastAPI + SPA), bound to 127.0.0.1
|
||||||
|
│
|
||||||
|
├── same-host Ollama on 127.0.0.1:11434 (default)
|
||||||
|
│
|
||||||
|
└── OR an explicitly configured trusted-LAN Ollama
|
||||||
|
on another user-controlled machine
|
||||||
|
http://<host>:11434/v1 or https://<host>/v1
|
||||||
```
|
```
|
||||||
|
|
||||||
Supported v1 trusted-LAN inference path:
|
Read that as three separate rules:
|
||||||
|
|
||||||
```text
|
1. **The storyteller's own listener is loopback, in every run path.** Dev
|
||||||
Browser -> local FastAPI application -> explicitly approved LAN Ollama host
|
server, production server, and container alike. Nothing about the inference
|
||||||
```
|
choice changes it. Where a container must listen on `0.0.0.0` because a
|
||||||
|
published port cannot reach anything else, the port is published to the
|
||||||
|
host's loopback only.
|
||||||
|
2. **The inference endpoint is an outbound connection, chosen by the user.**
|
||||||
|
Same-host loopback is the default. A trusted-LAN host is a first-class,
|
||||||
|
supported v1 configuration — not a workaround and not a development-only
|
||||||
|
convenience.
|
||||||
|
3. **The two are independent.** Reaching a LAN Ollama never requires, and must
|
||||||
|
never cause, LAN exposure of the storyteller UI/API. There is no supported
|
||||||
|
v1 configuration in which the storyteller itself is reachable from the LAN.
|
||||||
|
|
||||||
The browser and storyteller API still remain loopback-bound by default. Supporting LAN inference does **not** expose the storyteller web application to the LAN.
|
### Transport to a trusted-LAN endpoint
|
||||||
|
|
||||||
|
A LAN inference host is often reached over **HTTPS with a certificate issued by
|
||||||
|
a private or local CA**, and may offer no cleartext port at all. This is
|
||||||
|
ordinary for a self-hosted server, so v1 must handle it rather than assume the
|
||||||
|
same plain HTTP that same-host loopback uses:
|
||||||
|
|
||||||
|
- outbound HTTPS verifies against the **operating system's trusted CA store** in
|
||||||
|
addition to any bundled certificate list, so a CA the user installed on their
|
||||||
|
own machine is honoured here as it is by `curl` and their browser;
|
||||||
|
- certificate **and hostname** verification stay fully enabled;
|
||||||
|
- there is **no "ignore TLS errors" option** anywhere — not in the UI, not in
|
||||||
|
configuration, not as an environment variable;
|
||||||
|
- the endpoint field therefore accepts `https://` on any port.
|
||||||
|
|
||||||
|
Prompts, story text, retrieved knowledge and embedding inputs all travel to
|
||||||
|
whichever inference host is configured, which is why it must be one the user
|
||||||
|
controls on a network they trust — and why the endpoint is always explicitly
|
||||||
|
configured, never discovered.
|
||||||
|
|
||||||
|
See ADR 002 (*Transport for a Trusted-LAN Endpoint*) and, for the demonstrated
|
||||||
|
deployment, `planning/reports/M1-IMPLEMENTATION-REPORT.md` §F.
|
||||||
|
|
||||||
Allowed future local paths may also include explicitly configured local media services.
|
Allowed future local paths may also include explicitly configured local media services.
|
||||||
|
|
||||||
@@ -161,17 +201,30 @@ Production defaults must not require:
|
|||||||
|
|
||||||
### 5.1 Known AI-DnD hardening work
|
### 5.1 Known AI-DnD hardening work
|
||||||
|
|
||||||
Phase 0B identified concrete inherited violations:
|
Phase 0B identified concrete inherited violations, and M1 added a fifth. Items
|
||||||
|
1, 2 and 5 are **resolved**; items 3 and 4 remain open and belong to M2.
|
||||||
|
|
||||||
1. `tiktoken` attempts to download the `cl100k_base` encoding on first use.
|
1. ~~`tiktoken` attempts to download the `cl100k_base` encoding on first use.~~
|
||||||
- production packaging must include/cache the required encoding or replace the dependency path so first story use is offline.
|
**Done in M1.** The encoding table is vendored in the tree and loaded
|
||||||
2. the SPA requests Google Fonts at runtime.
|
directly, with its SHA-256 verified against the digest `tiktoken` pins, so no
|
||||||
- fonts must be self-hosted or replaced with local/system fonts and CSP tightened.
|
code path in the tokenizer can reach the network.
|
||||||
|
2. ~~the SPA requests Google Fonts at runtime.~~
|
||||||
|
**Done in M1.** All three families are self-hosted, and the CSP names no
|
||||||
|
remote origin at all.
|
||||||
3. hosted/multi-user/auth/demo/analytics/Postgres/cloud-provider/QuickJS paths are unnecessary.
|
3. hosted/multi-user/auth/demo/analytics/Postgres/cloud-provider/QuickJS paths are unnecessary.
|
||||||
- remove them rather than merely hide them where practical.
|
- remove them rather than merely hide them where practical.
|
||||||
|
- **Open — M2.** M1 removed nothing, so this surface is unchanged from the
|
||||||
|
fork point.
|
||||||
4. endpoint validation must reflect this product's threat model.
|
4. endpoint validation must reflect this product's threat model.
|
||||||
- same-host loopback Ollama is the default; an explicitly configured trusted-LAN Ollama endpoint is supported; arbitrary public/Internet model endpoints must be rejected or kept outside normal v1 configuration.
|
- same-host loopback Ollama is the default; an explicitly configured trusted-LAN Ollama endpoint is supported; arbitrary public/Internet model endpoints must be rejected or kept outside normal v1 configuration.
|
||||||
- inference endpoint configuration must not change the storyteller's own loopback bind behavior.
|
- inference endpoint configuration must not change the storyteller's own loopback bind behavior.
|
||||||
|
- **Open — M2.** The trusted-LAN path itself works as of M1; what remains is
|
||||||
|
deciding and enforcing which endpoints normal v1 configuration may name.
|
||||||
|
5. ~~outbound TLS verified only against a bundled public-CA list, so a LAN host
|
||||||
|
with a privately issued certificate was refused.~~
|
||||||
|
**Found and fixed in M1.** Not visible to Phase 0B: every run up to that
|
||||||
|
point used plain HTTP over loopback, where certificate verification never
|
||||||
|
happens. See *Transport to a trusted-LAN endpoint* above.
|
||||||
|
|
||||||
## 6. Browser UI Boundary
|
## 6. Browser UI Boundary
|
||||||
|
|
||||||
|
|||||||
@@ -64,10 +64,13 @@ Recommended environment:
|
|||||||
- one installed narrator model,
|
- one installed narrator model,
|
||||||
- one installed embedding model if semantic retrieval is enabled,
|
- one installed embedding model if semantic retrieval is enabled,
|
||||||
- outbound Internet blocked after setup,
|
- outbound Internet blocked after setup,
|
||||||
- fresh test data directory.
|
- fresh test data directory,
|
||||||
|
- for A06, a second user-controlled machine on the trusted LAN serving HTTPS
|
||||||
|
with a locally issued certificate.
|
||||||
|
|
||||||
Record:
|
Record:
|
||||||
- OS,
|
- OS,
|
||||||
|
- **CPU (core count), GPU (or explicitly none), and RAM**,
|
||||||
- application commit/version,
|
- application commit/version,
|
||||||
- Ollama version,
|
- Ollama version,
|
||||||
- narrator model,
|
- narrator model,
|
||||||
@@ -75,6 +78,14 @@ Record:
|
|||||||
- browser,
|
- browser,
|
||||||
- test date.
|
- test date.
|
||||||
|
|
||||||
|
Hardware is not bookkeeping. A model's **cold load** time depends on it, and
|
||||||
|
M1 measured a cold `qwen2.5:3b-instruct` load on a GPU-less four-core host
|
||||||
|
exceeding the inherited 120-second client timeout — three times — while the
|
||||||
|
same turn completed in 6 to 9 seconds once the model was resident. A timeout
|
||||||
|
result is therefore uninterpretable unless the hardware and the warm/cold state
|
||||||
|
are recorded with it, and a pass on a GPU machine does not predict a pass on a
|
||||||
|
CPU-only one.
|
||||||
|
|
||||||
## 4. Standard Test Campaign
|
## 4. Standard Test Campaign
|
||||||
|
|
||||||
Create a campaign named:
|
Create a campaign named:
|
||||||
@@ -284,9 +295,29 @@ Transcript and authoritative current state are restored.
|
|||||||
5. Reopen campaign.
|
5. Reopen campaign.
|
||||||
|
|
||||||
### Pass
|
### Pass
|
||||||
- prior story remains intact,
|
- **previously accepted history and state are unchanged** — every earlier turn,
|
||||||
- failed turn is not partially committed as accepted,
|
its text and the authoritative state remain exactly as they were,
|
||||||
- user can retry.
|
- **no AI response is accepted for the failed turn**: no partial or truncated
|
||||||
|
narration is committed, and the count of accepted AI turns does not move,
|
||||||
|
- the failure is reported to the user rather than swallowed,
|
||||||
|
- the user can retry and continue.
|
||||||
|
|
||||||
|
### Note on wording
|
||||||
|
|
||||||
|
"Nothing was committed" would be misleading, and this test should not be read
|
||||||
|
that way. The user's **submitted text is deliberately retained**: it is
|
||||||
|
committed before the model is called, so a model failure never discards what
|
||||||
|
the player typed. A failed turn therefore leaves the player's input at the head
|
||||||
|
of the story with no reply, and the total row count grows by one.
|
||||||
|
|
||||||
|
The invariant is about *accepted* history, not about row counts. What must
|
||||||
|
never happen is a partially generated AI response entering the story as though
|
||||||
|
it were accepted, or an earlier turn being altered or lost.
|
||||||
|
|
||||||
|
A test that asserts the story is byte-identical before and after will fail for
|
||||||
|
the wrong reason. Assert instead on the accepted prefix — for example, a digest
|
||||||
|
over every action up to the pre-failure head — and on the number of accepted AI
|
||||||
|
turns.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -296,13 +327,18 @@ Transcript and authoritative current state are restored.
|
|||||||
|
|
||||||
### Preconditions
|
### Preconditions
|
||||||
- storyteller and browser run on machine A,
|
- storyteller and browser run on machine A,
|
||||||
- Ollama runs on a separate user-controlled machine B on the trusted LAN,
|
- Ollama runs on a separate user-controlled machine B on the trusted LAN —
|
||||||
|
**a genuinely separate machine**, not another container or namespace on
|
||||||
|
machine A,
|
||||||
|
- **machine B serves HTTPS with a certificate issued by a private/local CA**,
|
||||||
|
and that CA is installed in machine A's operating-system trust store,
|
||||||
- required models are already installed,
|
- required models are already installed,
|
||||||
- outbound Internet access is blocked.
|
- outbound Internet access is blocked.
|
||||||
|
|
||||||
### Steps
|
### Steps
|
||||||
1. Keep the storyteller UI/API bound to loopback on machine A.
|
1. Keep the storyteller UI/API bound to loopback on machine A.
|
||||||
2. Configure the storyteller's Ollama endpoint to machine B.
|
2. Configure the storyteller's Ollama endpoint to machine B, as an `https://`
|
||||||
|
URL using the hostname the certificate is issued for.
|
||||||
3. Verify model discovery/connection diagnostics.
|
3. Verify model discovery/connection diagnostics.
|
||||||
4. Generate at least three story turns.
|
4. Generate at least three story turns.
|
||||||
5. Trigger state extraction and embeddings/memory retrieval if enabled.
|
5. Trigger state extraction and embeddings/memory retrieval if enabled.
|
||||||
@@ -311,11 +347,28 @@ Transcript and authoritative current state are restored.
|
|||||||
|
|
||||||
### Pass
|
### Pass
|
||||||
- story operation succeeds through the explicitly configured LAN Ollama host,
|
- story operation succeeds through the explicitly configured LAN Ollama host,
|
||||||
|
- **TLS is verified, not bypassed**: the certificate chains to the CA installed
|
||||||
|
on machine A and the hostname is checked; no "insecure" option was used,
|
||||||
|
because none exists,
|
||||||
- no cloud API key or Internet access is required,
|
- no cloud API key or Internet access is required,
|
||||||
- inference/model traffic goes only to the approved LAN host,
|
- inference/model traffic goes only to the approved LAN host,
|
||||||
- storyteller UI/API remains loopback-bound,
|
- storyteller UI/API remains loopback-bound,
|
||||||
- prompts, state, retrieved knowledge, and embedding inputs do not go to any unapproved destination.
|
- prompts, state, retrieved knowledge, and embedding inputs do not go to any unapproved destination.
|
||||||
|
|
||||||
|
### Note on sufficient evidence
|
||||||
|
|
||||||
|
Added after M1. **A plain-HTTP LAN test is no longer sufficient evidence for
|
||||||
|
this test.** Certificate verification never happens over cleartext, so an
|
||||||
|
HTTP-only run cannot exercise the path that actually broke: against a real
|
||||||
|
HTTPS LAN host, the application refused an endpoint that `curl` and the browser
|
||||||
|
on the same machine accepted, because it verified against a bundled public-CA
|
||||||
|
list instead of the machine's own trust store (ADR 002, *Transport for a
|
||||||
|
Trusted-LAN Endpoint*).
|
||||||
|
|
||||||
|
A container or network namespace standing in for machine B is likewise not
|
||||||
|
sufficient on its own. It exercises the non-loopback address but typically
|
||||||
|
speaks plain HTTP, and it will hide exactly this class of defect.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# B. Basic Story Interaction
|
# B. Basic Story Interaction
|
||||||
|
|||||||
+34
-3
@@ -1,8 +1,39 @@
|
|||||||
# Planning Package Version
|
# Planning Package Version
|
||||||
|
|
||||||
**Package:** Adventure Storyteller Planning Package v2
|
**Package:** Adventure Storyteller Planning Package v2.1
|
||||||
**Revision date:** 2026-09-01
|
**Revision date:** 2026-09-02
|
||||||
**Status:** Phase 0 complete; architecture selected; production milestone plan approved for milestone-by-milestone implementation.
|
**Status:** Phase 0 complete; architecture selected; **Milestone M1 implemented and accepted**; M2 not yet briefed.
|
||||||
|
|
||||||
|
## v2.1 — Post-M1 Corrections (2026-09-02)
|
||||||
|
|
||||||
|
M1 implementation evidence contradicted or under-specified parts of v2. The
|
||||||
|
corrections are recorded in the documents themselves and listed in
|
||||||
|
`README.md` § *Post-M1 corrections applied*; the evidence behind them is in
|
||||||
|
`reports/M1-BASELINE-REPORT.md` and `reports/M1-IMPLEMENTATION-REPORT.md`.
|
||||||
|
|
||||||
|
In summary:
|
||||||
|
|
||||||
|
- a trusted-LAN Ollama may be **HTTPS with a privately issued certificate**;
|
||||||
|
clients verify against the operating system's CA store, with full certificate
|
||||||
|
and hostname verification and no bypass option (ADR 002,
|
||||||
|
`TECHNICAL-DESIGN.md` §5, A06),
|
||||||
|
- offline claims require a **fresh cache and no route out** to be evidence at
|
||||||
|
all, and vendored runtime artifacts should be integrity-verifiable
|
||||||
|
(ADR 004),
|
||||||
|
- A05's invariant is about **accepted** history; the user's submitted text is
|
||||||
|
deliberately retained on a failed turn,
|
||||||
|
- A06 requires a **real second machine and an HTTPS endpoint**; a plain-HTTP
|
||||||
|
LAN test is no longer sufficient evidence,
|
||||||
|
- the standard test environment records **CPU/GPU/RAM**, because cold model
|
||||||
|
load on a CPU-only host exceeded the inherited 120 s client timeout,
|
||||||
|
- `BUILD-MILESTONES.md` records M1 as complete and reframes M2's endpoint work
|
||||||
|
as **narrowing** an existing capability rather than inventing it,
|
||||||
|
- `SECURITY-THREAT-MODEL.md` §53 distinguishes **inbound** TLS (still deferred)
|
||||||
|
from **outbound** certificate verification (required, done in M1).
|
||||||
|
|
||||||
|
Nothing in the architecture selected in v2 was reversed.
|
||||||
|
|
||||||
|
## v2 — Post Phase 0B Revision (2026-09-01)
|
||||||
|
|
||||||
This v2 package supersedes the earlier planning package produced before the final Phase 0B review and the trusted-LAN Ollama deployment clarification.
|
This v2 package supersedes the earlier planning package produced before the final Phase 0B review and the trusted-LAN Ollama deployment clarification.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user