Skip to content

feat(demo): Vue/Pinia/Router shell bootstrap + petCare salvage (Pillar-1 slice 1.2a)#146

Merged
Luis85 merged 6 commits into
developfrom
feat/tour-shell-1-2a
Apr 26, 2026
Merged

feat(demo): Vue/Pinia/Router shell bootstrap + petCare salvage (Pillar-1 slice 1.2a)#146
Luis85 merged 6 commits into
developfrom
feat/tour-shell-1-2a

Conversation

@Luis85
Copy link
Copy Markdown
Owner

@Luis85 Luis85 commented Apr 26, 2026

Summary

Pillar-1 slice 1.2a of the pre-v1 demo evolution: bootstrap the
Vue 3 SFC + Pinia 2 + Vue Router 4 application shell without
rewiring the live entry. The Wave-0 bridge in
examples/product-demo/src/app/main.ts keeps booting the legacy demo
via await import('../main.js') — slice 1.2b is what swaps the mount.

  • git mv salvage (history preserved) of the pet-care scenario's
    pure modules into src/demo-domain/scenarios/petCare/: species.ts,
    constants.ts, cognition/{heuristic,bt,bdi,learning,index}.ts +
    learning.network.json, skills/ApproachTreatSkill.ts.
  • New demo-domain/scenarios/petCare/buildAgent.ts factory extracts
    the random-event defs + skill-registry wiring + createAgent recipe
    from the legacy src/main.ts so the upcoming Pinia store and the
    Wave-0 bridge can share a single source of truth without a
    behavioural change. Pure TS — no DOM, no Pinia.
  • useAgentSession Pinia domain store wraps buildAgent: owns the
    live Agent (via markRaw), persists the seed under
    demo.v2.session.lastSeed.<scenarioId> per design's STO contract,
    and exposes init / tick / start / pause / resume / step /
    setSpeed / replayFromSnapshot / subscribe. The tick driver
    lives outside the store on purpose so requestAnimationFrame stays
    out of stores/domain/** (NFR-D-1). Pre-v1 clean break: legacy
    whiskers / agentonomous/seed keys are not migrated.
  • Vue infrastructure scaffolded but NOT live yet: app/App.vue,
    routes/index.ts, views/{IntroView,PlayView}.vue,
    components/shell/AppHeader.vue, composables/ (empty),
    vue-shims.d.ts for tsc --noEmit.
  • Workspace deps added to examples/product-demo/package.json
    (vue, pinia, vue-router, @vue/test-utils, @pinia/testing,
    vue-eslint-parser, eslint-plugin-vue, @types/node) plus the
    same Vue/Pinia/Router/test-utils set to root package.json so root
    npm ci keeps tsc --noEmit and root vitest resolution working
    without a demo workspace install.
  • examples/product-demo/eslint.config.js: drops relocated paths
    from ignores, wires vue-eslint-parser + eslint-plugin-vue
    flat/recommended for *.vue files, opts SFCs + the Vue type shim
    out of the no-default-export structural rule.
  • Test: examples/product-demo/test/stores/domain/useAgentSession.test.ts
    under @pinia/testing covers init, persistence, tick, pause / resume,
    step (single-tick while paused), setSpeed, replayFromSnapshot (null
    reset path + 1.2b-deferred snapshot path), and subscribe.
  • Cross-package test imports updated for the moved petCare modules
    (tests/examples/btMode.test.ts, tests/examples/learningMode.train.test.ts,
    tests/unit/cognition/adapters/TfjsReasoner.test.ts).

Out of scope (slice 1.2b owns these)

  • app/main.ts rewrite (replace bridge with Vue mount).
  • Legacy src/{main,ui,traceView,seed}.ts deletion.
  • HudPanel / SpeedPicker / ResetButton / ExportImportPanel / TracePanel /
    TourOverlay / StepHighlight / chapter-1 step content.
  • useTourProgress view store + tour copy tone (OQ-P1) decision.
  • Snapshot deserialisation in replayFromSnapshot (today the action
    throws when given a non-null snapshot — explicit slice-1.2b TODO).

cognitionSwitcher.ts, lossSparkline.ts, predictionStrip.ts, and
speciesConfig.ts deliberately stay in place: Pillar 2 slice 2.5 ports

  • deletes the first three; Pillar 4 slice 4.3 deletes speciesConfig.ts.

Test plan

  • npm run verify (format:check + lint + lint:demo + typecheck +
    test + build + docs) — green locally on Windows / Node 22.
  • 580 vitest tests pass, including the new useAgentSession suite
    (10 cases) and the slice-1.1 walkthrough domain tests.
  • npm run lint:demo clean for the new vue-eslint-parser + Vue
    plugin wiring (placeholder SFCs, type shim, store, test).
  • Codex review (this PR opens with @codex review per project
    workflow; auto-poll cron arms after the request).

Tracks: #132

🤖 Generated with Claude Code

…r-1 slice 1.2a)

Bootstrap the Vue 3 SFC + Pinia 2 + Vue Router 4 application shell
without rewiring the live entry yet. The Wave-0 bridge in
`examples/product-demo/src/app/main.ts` keeps booting the legacy demo
via `await import('../main.js')` — slice 1.2b is what swaps it.

Salvage (`git mv`, history preserved) of the pet-care scenario's pure
modules into `src/demo-domain/scenarios/petCare/`:

- `species.ts`, `constants.ts`
- `cognition/{heuristic,bt,bdi,learning,index}.ts` + `learning.network.json`
- `skills/ApproachTreatSkill.ts`

New `demo-domain/scenarios/petCare/buildAgent.ts` factory extracts the
random-event defs + skill-registry wiring + `createAgent` recipe from
the legacy `src/main.ts` so the upcoming Pinia store and the Wave-0
bridge can share a single source of truth without a behavioural change.
The legacy `src/main.ts` now consumes `buildAgent` rather than inlining
the recipe; `src/main.ts`'s side-effect chain (learning agent wiring,
modifier decorator, RAF loop, UI mounts) is untouched and follows in
slice 1.2b.

Vue infrastructure scaffolded but NOT live yet:

- `app/App.vue` (root component shell)
- `routes/index.ts` (route map per design contract)
- `views/{IntroView,PlayView}.vue` placeholders
- `components/shell/AppHeader.vue`
- `composables/` (empty cross-cutting hooks folder)
- `vue-shims.d.ts` for `*.vue` typing under `tsc --noEmit`

`useAgentSession` Pinia domain store wraps `buildAgent`: owns the live
`Agent` (via `markRaw`), persists the seed under
`demo.v2.session.lastSeed.<scenarioId>` per design's STO contract, and
exposes `init` / `tick` / `start` / `pause` / `resume` / `step` /
`setSpeed` / `replayFromSnapshot` / `subscribe`. Tick driver lives
outside the store on purpose so `requestAnimationFrame` stays out of
`stores/domain/**` (NFR-D-1). Pre-v1 clean break: legacy `whiskers`
and `agentonomous/seed` keys are NOT migrated.

Workspace deps:
- demo: `vue@^3`, `pinia@^2`, `vue-router@^4`, `@vue/test-utils`,
  `@pinia/testing`, `vue-eslint-parser`, `eslint-plugin-vue`,
  `@types/node`
- root: `vue`, `pinia`, `vue-router`, `@vue/test-utils`,
  `@pinia/testing` (so root vitest + `tsc --noEmit` resolve them
  without a demo workspace install)

`examples/product-demo/eslint.config.js`:
- Drops the relocated paths from `ignores` (now lint-covered under
  `demo-domain/scenarios/petCare/`).
- Wires `vue-eslint-parser` + `eslint-plugin-vue` flat/recommended for
  `*.vue` files.
- Opts SFCs + the Vue type shim out of the structural
  `no-default-export` rule.

Tests: `examples/product-demo/test/stores/domain/useAgentSession.test.ts`
(under `@pinia/testing`) covers init / persistence / tick / pause /
resume / step / setSpeed / replayFromSnapshot / subscribe paths.
Cross-package test imports updated for the moved petCare modules.

Tracks: #132

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Riding with the same PR that lands the work, per CLAUDE.md
"Plan + doc updates ride with the PR".

Tracks: #132

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 26, 2026

Coverage report

Metric This PR vs base Floor Status
statements 77.69% ⬆️ +0.55pp 74%
branches 67.93% ⬆️ +0.54pp 64%
functions 85.62% ⬇️ -0.11pp 83%
lines 79.25% ⬆️ +0.64pp 75%

Floors live in scripts/coverageThresholds.mjs (drift envelope 5pp). Re-baseline by editing that file when ⚠️ appears above; cite the new measured value + commit SHA.

@Luis85
Copy link
Copy Markdown
Owner Author

Luis85 commented Apr 26, 2026

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

Summary

Testing

  • npx vitest run examples/product-demo/test/stores/domain/useAgentSession.test.ts
  • ⚠️ npx eslint examples/product-demo/src/stores/domain/useAgentSession.ts examples/product-demo/test/stores/domain/useAgentSession.test.ts (environment limitation: vue-eslint-parser is not available in the current install, so ESLint cannot load examples/product-demo/eslint.config.js)

View task →

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 26, 2026

size-limit report 📦

Path Size
dist/index.js (gzip) 37.86 KB (0%)
dist/integrations/excalibur/index.js (gzip) 1.4 KB (0%)
dist/cognition/adapters/mistreevous/index.js (gzip) 1.14 KB (0%)
dist/cognition/adapters/js-son/index.js (gzip) 1.36 KB (0%)
dist/cognition/adapters/tfjs/index.js (gzip) 8.74 KB (0%)

Codex flagged that `setSpeed` accepted any number: non-finite or
non-positive values would either reach `agent.setTimeScale` (which
throws after `speedMultiplier` had already been mutated) or — for
`0` — silently shadow `pause()`'s contract.

Throw `RangeError` up front when `Number.isFinite(multiplier)` is
false or `multiplier <= 0`, so the store's invariants stay
consistent. Test exercises `0`, negative, `NaN`, and ±`Infinity`
and asserts the rejected call leaves `speedMultiplier` and
`agent.getTimeScale()` unchanged.

Tracks: #132

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Luis85
Copy link
Copy Markdown
Owner Author

Luis85 commented Apr 26, 2026

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8849aedd2e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +76 to +77
agent.value = markRaw(
buildAgent({
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Wire learning-mode agent context after session init

init() creates a fresh agent via buildAgent(...) but never calls setLearningAgent(...), which cognition/learning.ts relies on to set the persisted-network scope and keep mood/recent-event feature state in sync. In the upcoming Vue shell path that uses useAgentSession, switching to Learning mode will ignore previously trained snapshots (agentIdForHydration stays null) and run with stale feature inputs, unlike the legacy path in src/main.ts that explicitly wires this immediately after construction.

Useful? React with 👍 / 👎.

Comment on lines +112 to +114
if (!wasRunning) agent.value.setTimeScale(BASE_TIME_SCALE * speedMultiplier.value);
await agent.value.tick(dtSeconds);
if (!wasRunning) agent.value.setTimeScale(0);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restore paused scale in step with finally

When step() is invoked while paused, it temporarily raises timeScale before await agent.tick(dtSeconds), then lowers it afterward; if tick() throws (for example from a reasoner/runtime error), the restore path is skipped and the agent stays unpaused even though running remains false. Wrapping the tick await in try/finally avoids leaving control state inconsistent after failed single-step attempts.

Useful? React with 👍 / 👎.

… round 2)

P1 — useAgentSession.init now calls setLearningAgent on the freshly
built agent (and again in replayFromSnapshot's reset path), matching
the legacy src/main.ts contract. Without it, the upcoming Vue shell
path would have switched to Learning mode with a null
agentIdForHydration scope and stale mood / recent-event feature
inputs.

P2 — useAgentSession.step now wraps the awaited tick in try/finally
so the paused-scale invariant survives a thrown tick (reasoner /
runtime errors). Test mocks agent.tick to reject and asserts
getTimeScale() stays at 0 + running stays false.

Tracks: #132

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Luis85
Copy link
Copy Markdown
Owner Author

Luis85 commented Apr 26, 2026

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c3deba8efb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +31 to +32
import vueParser from 'vue-eslint-parser';
import vuePlugin from 'eslint-plugin-vue';
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Mirror new ESLint Vue deps in root install

Importing vue-eslint-parser and eslint-plugin-vue here makes npm run lint:demo depend on those packages, but they were only added to examples/product-demo/package.json while the repo’s root verify flow runs cd examples/product-demo && eslint . after a root npm ci (no workspaces). In a clean CI/local environment this causes module-resolution failures before linting starts. Please add these two packages to the root devDependencies (and lockfile) alongside the other mirrored demo deps.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c3deba8efb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +89 to +92
// a null hydration scope and stale feature inputs (mood / recent
// events).
setLearningAgent(fresh);
running.value = true;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Port random-event modifier wiring into session init

init() wires only setLearningAgent, but the legacy flow also subscribes to RandomEvent and applies sick/happy-glow/dirty/disobedient modifiers (src/main.ts does this today). In the new store-driven path, mildIllness, surpriseTreat, and messyPlay will no longer mutate state, so core gameplay loops (clean/scold pressure and illness penalties) silently disappear once the shell switches to useAgentSession.

Useful? React with 👍 / 👎.

);
}
const fresh = markRaw(buildAgent({ seed: seed.value }));
agent.value = fresh;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Rebind store subscribers after rebuilding the agent

replayFromSnapshot(null) replaces agent.value with a fresh instance, but subscribe() listeners are attached to the previous agent object. Any consumer that subscribed once (e.g., AGENT_TICKED-driven view stores) will stop receiving events after a reset/replay unless it manually resubscribes, which breaks the in-place reset flow.

Useful? React with 👍 / 👎.

…int deps (Codex round 3)

P1 — `buildAgent` now wires the random-event modifier reactions
(`sick` / `happy-glow` / `dirty` / `disobedient`) verbatim from the
legacy `src/main.ts` decorator block via a private
`wirePetCareEventModifiers(agent)` helper. The duplicate listener +
`unsubscribeModifierDecorator` cleanup are removed from `src/main.ts`
to avoid double-applying modifiers under the Wave-0 bridge. The new
`useAgentSession` store path now inherits the gameplay-critical
modifier side-effects without a separate wire-up step.

P1 — `vue-eslint-parser` and `eslint-plugin-vue` mirrored to root
`devDependencies` so a clean `npm ci` at the repo root keeps
`npm run lint:demo` resolvable from `examples/product-demo/`. Local
`npm run verify` no longer requires a prior demo workspace install for
the lint step.

P2 — `useAgentSession.subscribe` now tracks each listener in a
`SubscriberRecord` set; `init` and `replayFromSnapshot` call
`rebindSubscribers(fresh)` to detach from the previous agent and
re-attach to the rebuilt one. Reset/replay no longer silently breaks
AGENT_TICKED-driven view stores. Test exercises the rebind across a
`replayFromSnapshot(null)` and verifies the unsub stops events
afterwards.

Tracks: #132

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Luis85
Copy link
Copy Markdown
Owner Author

Luis85 commented Apr 26, 2026

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 393d649f63

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

'useAgentSession.replayFromSnapshot: snapshot deserialisation lands in slice 1.2b',
);
}
const fresh = markRaw(buildAgent({ seed: seed.value }));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reapply species override when rebuilding from snapshot

init() can construct the session with a speciesOverride, but replayFromSnapshot(null) rebuilds the agent with only the seed. In flows where a non-default species config is active (e.g., after loading an override), pressing reset/replay will silently revert behavior to catSpecies, so subsequent ticks no longer match the session the user configured. Persist the last applied override in store state and pass it back into buildAgent(...) during replay rebuilds.

Useful? React with 👍 / 👎.

… (Codex round 4)

`init()` accepted a `speciesOverride` but discarded it after
`buildAgent`, so `replayFromSnapshot(null)` rebuilt the agent with the
scenario default — silently reverting any active config override on
reset / replay.

Track the last applied override in a `lastSpeciesOverride` ref, set it
in `init` (clearing it when no override is supplied), and pass it back
into `buildAgent` from `replayFromSnapshot(null)`. Tests cover the
override-survives-replay path (asserting needs IDs round-trip via the
rebuilt agent's getState) and the clear-on-plain-init path.

Tracks: #132

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Luis85
Copy link
Copy Markdown
Owner Author

Luis85 commented Apr 26, 2026

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b9452ec152

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 483 to 486
const baselinePath = path.resolve(
process.cwd(),
'examples/product-demo/src/cognition/learning.network.json',
'examples/product-demo/src/demo-domain/scenarios/petCare/cognition/learning.network.json',
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep seed script output path in sync with moved baseline file

Now that the baseline is loaded from examples/product-demo/src/demo-domain/scenarios/petCare/cognition/learning.network.json, the regeneration workflow is out of sync: scripts/seed-learning-network.ts still writes to examples/product-demo/src/cognition/learning.network.json (a directory removed by this move). Running npm run seed:learning-network will therefore fail or update the wrong location, so developers cannot regenerate the JSON consumed here.

Useful? React with 👍 / 👎.

@Luis85 Luis85 merged commit dd1ed51 into develop Apr 26, 2026
25 checks passed
@Luis85 Luis85 deleted the feat/tour-shell-1-2a branch April 26, 2026 18:25
@Luis85 Luis85 added the roadmap:v1-demo Pre-v1 product-demo evolution: walkthrough, cognition diff, fingerprint, editor, second scenario label May 5, 2026
@Luis85 Luis85 mentioned this pull request May 11, 2026
15 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

roadmap:v1-demo Pre-v1 product-demo evolution: walkthrough, cognition diff, fingerprint, editor, second scenario

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants