Skip to content

Learning engagement context and Nina harness#187

Merged
nabilfatih merged 11 commits into
mainfrom
codex/learning-engagement-context
Jun 22, 2026
Merged

Learning engagement context and Nina harness#187
nabilfatih merged 11 commits into
mainfrom
codex/learning-engagement-context

Conversation

@nabilfatih

@nabilfatih nabilfatih commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

Source of truth

Final accepted plan v3: file:///private/tmp/nakafa-education-agent-harness-final-plan-v3-20260622-1635.html

Latest pushed SHA: 09d666ca7e688500ad804e1b1a9a364aafefefd6

PR state: ready for review, not draft. Title remains exactly Learning engagement context and Nina harness.

Current readiness state

Implementation, local verification, Convex dev/prod deployment, GitHub checks, review-thread cleanup, root-start runtime proof, Browser-plugin proof for unchanged app/UI surfaces, and the latest engagement identity review-body blocker fix are current for PR #187.

PR #187 is not mergeable until required human review approves it: reviewDecision=REVIEW_REQUIRED.

Latest check state at body update time on 09d666ca7e:

  • React Doctor: pass, score 100/100.
  • react-doctor: pass.
  • agent-docs: pass.

Thread-aware GraphQL review-thread checks previously returned no unresolved current or outdated inline review threads. The later Codex Review body comments on packages/backend/convex/contents/views/impl.ts:112 are addressed by 09d666ca7e; they were body comments on older reviewed commits, not unresolved inline threads.

Final-plan-v3 implementation matrix

  • One public app-facing Nina Interface remains NinaHarness.stream; route/framework code knows request/auth plus the harness entry point.
  • AI SDK ToolLoopAgent, prepareStep, writer, repair, model/runtime, stream response composition, specialist routing, suggestions, and trace handling stay inside packages/ai/nina internals.
  • Fake packages/ai/agents/orchestrator ownership was deleted/absorbed into nina/prompt, nina/policy, and nina/capability.
  • LearningCapability, EvidenceEnvelope, LearningCapabilityResult, CapabilityTrace, eval, Nina turn/context, and expected failures derive from Effect Schema/Class/TaggedError, Convex validators/generated types, AI SDK exported interop types, or Effect services/layers.
  • Math/Nakafa/research specialists remain capability Modules behind NinaHarness.stream; deterministic policy handles simple routing, math truth is evidence-first, and research is reserved for source-heavy/current/external work.
  • Convex persists bounded capability trace summaries only, with owner-scoped indexed reads and retention cleanup; canonical chat/content/learning/counter data is not deleted by trace retention.
  • Homepage Continue Learning and popularity read from materialized read models/current route rows; no request-time raw-event homepage scans.

Engagement identity blocker handling on 09d666c

Fixed the Codex Review body concerns around packages/backend/convex/contents/views/impl.ts:112 by making the learningViews contract explicit and indexed:

  • learningViews are now documented as one row per anonymous device or authenticated user-device for each canonical asset and verified context.
  • Added learningViews.by_userId_and_deviceId_and_content_id_and_contextKey so signed-in requests can load only their own row on the current device.
  • Added learningViews.by_deviceId_and_content_id_and_contextKey_and_lastViewedAt so unsigned device reads are indexed, bounded, and latest-row aware when multiple accounts have used the same browser/device.
  • Signed-in requests may mutate their exact user-device row or claim an anonymous device row. They no longer mutate another signed-in learner's row and no longer fall back to a different-device user row.
  • Same signed-in learner across devices now gets separate user-device view rows, while popularity remains deduped by the existing user:<id> viewer key.
  • Unsigned repeats of a signed-in row are treated as already viewed without mutating that user-owned row, so the learningViews trigger does not emit a product analytics event for a previous signed-in user.
  • Different signed-in users on one device create separate rows, separate recents, separate user-scoped popularity signals, and product analytics events for the correct user.

Regression proof added in packages/backend/convex/contents/mutations/views.test.ts:

  • Two different signed-in users on one device/content/context produce separate learningViews ownership, separate userLearningRecents, and content-view analytics scheduled for each correct user only.
  • One signed-in learner on device A then device B creates two user-device rows but one same-day popularity signal; a later signed-out repeat on device B creates no second same-day popularity contribution.
  • Anonymous-to-signed-in same-device still links the anonymous row without duplicate popularity.
  • Signed-in-to-signed-out same-device is now explicitly deduped without mutating signed-in ownership or emitting another content-view product event.

Review-thread handling before 09d666c

Earlier final-plan-v3 blockers remain fixed: pinned Nina context after transcript rewrites, exact-size transcript rewrites, signed-in view keys, paged Continue Learning recents, paged trending counters, atomic transcript replacement, trace retention cron, paged audio popularity reads, and bounded capability trace summaries.

The immediately previous pushed fix on 207a461bda handled:

  • apps/www/app/api/chat/route.ts:160 / “Resolve pinned context after rewrite deletion”: the route passes message.id into loadPinnedNinaContext; Convex getPinnedNinaContextForTurn finds an existing message by identifier and reads only retained transcript messages using messages.by_chatId with _creationTime < rewrite point, bounded to 20. This excludes soon-deleted tail snapshots without app-side pre-delete, while saveMessage remains the atomic replacement mutation.
  • packages/backend/convex/chats/mutations.ts:145 / “Allow exact-size transcript rewrites”: deleteMessageBatchFromPoint reads CHAT_TRANSCRIPT_REWRITE_MESSAGE_BATCH_SIZE + 1 rows as a sentinel, deletes only the supported slice, and reports overflow only when the sentinel exists. Exact 25-message rewrites succeed; 26+ still rejects transactionally through the existing saveMessage error path.

Verification commands on 09d666c

Passed locally from repo root:

pnpm --filter @repo/backend exec vitest run convex/contents/mutations/views.test.ts convex/triggers/contents/views.test.ts
pnpm --filter @repo/backend typecheck
pnpm format
pnpm lint
pnpm build
pnpm run doctor --verbose --diff
git diff --check

Observed proof:

  • Backend content-view mutation + trigger focused suites: 13 passed / 13.
  • Backend typecheck: passed.
  • pnpm build: 17 successful tasks, including full backend tests (145 files / 629 tests), full www tests (82 files / 722 tests), and production www build.
  • pnpm run doctor --verbose --diff: 100/100, no changed-source diagnostics.
  • pnpm format and pnpm lint: passed with the pre-existing Ultracite warning that packages/contents/quran/source.ts exceeds the configured max file size.
  • git diff --check: clean before commit.
  • Touched production seam scan over packages/backend/convex/contents/views/impl.ts and packages/backend/convex/contents/schema.ts found no raw try/catch, unsafe casts, any, ts-ignore/ts-expect-error, generic thrown expected failures, or Effect runners. The only match was the existing Effect.tryPromise wording in JSDoc.
  • Worktree is clean after pushing 09d666ca7e.

Convex deploy and data proof on 09d666c

Dev deployment:

pnpm --filter @repo/backend exec convex dev --once

Result: current Convex functions ready on dev deployment cheerful-ocelot-306; both new learningViews indexes were added.

Authorized production deployment:

pnpm --filter @repo/backend exec convex deploy --yes --message "PR #187 learning view identity ownership 09d666ca7e688500ad804e1b1a9a364aafefefd6"

Result: no indexes deleted, functions uploaded, TypeScript checked, schema validation complete, production functions deployed to dapper-antelope-269, and both new learningViews indexes were added.

Dev/prod function-spec verification confirmed the current content-view mutation surface:

pnpm --filter @repo/backend exec convex function-spec | rg 'contents/mutations/views.js:recordContentView|recordContentView'
pnpm --filter @repo/backend exec convex function-spec --prod | rg 'contents/mutations/views.js:recordContentView|recordContentView'

Both dev and prod expose contents/mutations/views.js:recordContentView after the current source deploy.

No schema/index deletion occurred in the production deploy. This patch adds indexes and changes selection semantics only; it does not delete or overwrite canonical chat messages, user learning evidence, content refs, lifetime counters/checkpoints, eval evidence, or durable engagement facts.

Browser/runtime proof

Fresh root pnpm start remains running from /Users/nabilfatih/.codex/worktrees/cde1/nakafa.com with www available at http://localhost:3000. Browser proof used the in-app Browser plugin visibly against http://localhost:3000; no external-browser proof was substituted.

Latest Browser-plugin proof was completed on 207a461bda before the Convex-only engagement identity follow-up. The follow-up commit did not change app UI/chat surfaces, but did receive targeted Convex tests and fresh dev/prod Convex deployment proof on 09d666ca7e.

Browser-plugin proof details:

  • Auth: http://localhost:3000/id/auth showed the authenticated state with Keluar; no password, MFA, CAPTCHA, or secret handling was attempted.
  • Home: /id/home rendered Hi, Nabil Fatih, Lanjutkan Belajar, and Materi Populer Minggu Ini.
  • Continue Learning: clicked Hukum Kekekalan Massa from home and landed on /id/materi/kimia/hukum-dasar-kimia/hukum-kekekalan-massa?ctx=merdeka~class-10-chemistry-basic-chemistry-laws.
  • Material context/header: material page rendered Hukum Dasar Kimia back/header link to /id/kurikulum/merdeka/kelas-10/kimia#hukum-dasar-kimia, plus Tanya Nina and page-outline context.
  • Next/previous: material next/previous links both preserved ctx=merdeka~class-10-chemistry-basic-chemistry-laws; clicked next to hukum-perbandingan-berganda?ctx=... and clicked previous back to hukum-kekekalan-massa?ctx=....
  • Language switching: direct locale route /en/subjects/chemistry/basic-chemistry-laws/mass-conservation-law?ctx=merdeka~class-10-chemistry-basic-chemistry-laws rendered English Mass Conservation content.
  • Rejected legacy route: /id/curricula/merdeka rendered 404 - Page Not Found.
  • Standalone Nina chat: /id/chat accepted Jelaskan hukum kekekalan massa dalam dua kalimat sederhana., created /id/chat/ks79s8mb5s58vtc6f8wfmhv0nx894395, returned a normal answer, and rendered follow-up suggestions including Berikan satu contoh dalam kehidupan sehari-hari tentang hukum ini., Apa yang terjadi kalau reaksinya dilakukan di wadah terbuka?, and Bisa berikan contoh soal sederhana untuk menghitung massa zat hasil reaksi?.
  • Material Nina context: from the material page, clicked Tanya Nina and asked Dari halaman ini, apa inti hukum kekekalan massa?; the sheet answered from verified page context, surfaced Materi / Hukum Kekekalan Massa, and returned no Waduh/error state. Root-start logs for that request show verified: true, assetId/contentId, materialKey: lesson.chemistry.basic-chemistry-laws, and placement parentHref: /id/kurikulum/merdeka/kelas-10/kimia#hukum-dasar-kimia.
  • Homepage popularity: clicked the visible Ciri-Ciri Reaksi Kimia card under Materi Populer Minggu Ini and landed on /id/materi/kimia/hukum-dasar-kimia/ciri-ciri-reaksi-kimia.
  • Representative flows: /id/kurikulum/merdeka/kelas-10/kimia rendered class-10 Chemistry curriculum topics; /id/try-out rendered authenticated SNBT try-out sets; /id/latihan/snbt/pengetahuan-kuantitatif/tryout-2026/set-1/soal-1 rendered the practice question page with choices and next/previous controls.

Structure/DX audit

The latest follow-up adds no wrapper chains, no new facade/barrel, no alias shim, no generic utility dump, and no temporary migration/backfill surface.

Current direct evidence:

  • learningViews now has explicit ownership indexes for the actual read seams instead of relying on ambiguous row fallback.
  • contents/views/impl.ts remains an Effect-native Convex implementation Module; private helpers split exact responsibilities: target resolution, latest device lookup, signed-in device lookup, safe existing-row selection, insert, update, recents, and signal enqueue.
  • The new schema indexes are permanent operational indexes for runtime reads, not migration helpers.
  • Tests cross the Convex mutation and trigger seams directly.

Touched latest-follow-up file sizes:

  • packages/backend/convex/contents/views/impl.ts: 349 LOC.
  • packages/backend/convex/contents/schema.ts: 456 LOC.
  • packages/backend/convex/contents/mutations/views.test.ts: 852 LOC. This test file was already a broad Convex mutation regression file and the user explicitly requested these identity regressions there; no production file exceeds the 500 LOC blocker in this follow-up.

Effect/schema contract audit

The latest changed Convex seam stays Effect-native:

  • View selection, inserts, updates, auth lookup, context resolution, recents, signal enqueue, and scheduling remain composed as Effect.fn programs with typed ContentViewIoError failures.
  • Convex read/write contracts derive from generated Doc/MutationCtx and schema validators; the new indexes are defined in the Convex schema source of truth.
  • Product analytics attribution remains trigger-owned by learningViews.userId, but unsigned repeats no longer mutate a user-owned row, so the trigger cannot emit an event for a previous signed-in user from an unsigned repeat.
  • Pure deterministic test helpers remain local and total except for assertion failures in tests.

Remaining TypeScript type/interface usage in this follow-up is limited to generated/library interop and local test helper shapes (Doc, MutationCtx, ReturnType<typeof createConvexTestWithBetterAuth>, scheduled job arg inspection).

Vercel applicability

No Vercel project configuration change is required for this follow-up. The PR changes Convex functions/schema plus tests; React Doctor, react-doctor, and agent-docs are green on 09d666ca7e. Final merge remains blocked only by required human review (reviewDecision=REVIEW_REQUIRED).

@github-actions

github-actions Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

React Doctor found no new issues. 🎉

Reviewed by React Doctor for commit 09d666c.

@nabilfatih nabilfatih self-assigned this Jun 22, 2026
@nabilfatih nabilfatih changed the title [codex] Learning engagement context and Nina harness Learning engagement context and Nina harness Jun 22, 2026
@nabilfatih nabilfatih marked this pull request as ready for review June 22, 2026 08:21

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

Copy link
Copy Markdown

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: 694a878d1d

ℹ️ 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 thread apps/www/app/api/chat/agent.ts Outdated
Comment thread packages/backend/convex/contents/constants.ts Outdated
Comment thread apps/www/app/api/chat/context.ts
Comment thread packages/backend/convex/contents/queries/recent.ts Outdated
@vercel vercel Bot temporarily deployed to Preview – mcp June 22, 2026 09:30 Inactive
@vercel

vercel Bot commented Jun 22, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Actions Updated (UTC)
api Skipped Skipped Jun 22, 2026 9:30am
mcp Skipped Skipped Jun 22, 2026 9:30am

Request Review

@vercel vercel Bot temporarily deployed to Preview – api June 22, 2026 09:30 Inactive

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

Copy link
Copy Markdown

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: f0e6f1b9df

ℹ️ 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 thread packages/ai/nina/agent.ts Outdated
Comment thread packages/backend/convex/contents/metrics/batch.ts
Comment thread packages/backend/convex/contents/views/impl.ts

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

Copy link
Copy Markdown

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: 2534043e4b

ℹ️ 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 thread apps/www/app/api/chat/route.ts Outdated
Comment thread packages/backend/convex/contents/views/impl.ts
Comment thread packages/backend/convex/curriculumLessons/trending/impl.ts Outdated

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

Copy link
Copy Markdown

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: d9bc537a57

ℹ️ 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 thread packages/ai/nina/runtime/stream.ts Outdated
Comment thread apps/www/lib/hooks/use-record-content-view.ts Outdated
Comment thread packages/backend/convex/contents/queries/recent.ts Outdated
Comment thread packages/backend/convex/curriculumLessons/trending/impl.ts

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

Copy link
Copy Markdown

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: 5c5adbdd20

ℹ️ 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 thread apps/www/lib/hooks/views.ts Outdated
Comment thread packages/backend/convex/curriculumLessons/trending/impl.ts Outdated
Comment thread packages/backend/convex/contents/queries/recent.ts Outdated
Comment thread apps/www/app/api/chat/route.ts Outdated
Comment thread packages/backend/convex/chats/traces/impl.ts
Comment thread packages/backend/convex/contents/queries/audio.ts Outdated
Comment thread packages/ai/nina/capability/result.ts Outdated

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

return existingByDevice ?? existingByUser;

P2 Badge Persist the current device on cross-device hits

When a signed-in learner first views content on device A and then on device B, this returns the existing user row from device A without recording device B anywhere. If the learner signs out on device B, the auth-aware client key sends an anonymous view, loadExistingView finds no device-B row, and popularity inserts a new device:<id> viewer signal because the anonymous path cannot check the prior user:<id> signal, so one learner can be counted twice for the same content/day.

ℹ️ 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 thread apps/www/app/api/chat/route.ts Outdated
Comment thread packages/backend/convex/chats/mutations.ts

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

return existingByDevice ?? existingByUser;

P2 Badge Avoid reusing another user’s device view

When the same browser/device is used by multiple signed-in accounts, this prefers the existing device row even if it already belongs to a different userId. In that case the later viewer never gets their own learningViews row (the update path won't replace a populated view.userId), and the learningViews trigger attributes the new view event to the previous user; only reuse the device row when it is anonymous or owned by the current user, otherwise fall through to the current user's row or insert a new one.

ℹ️ 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".

@nabilfatih

Copy link
Copy Markdown
Collaborator Author

Resolved the Codex Review body concerns around packages/backend/convex/contents/views/impl.ts:112 in 09d666ca7e688500ad804e1b1a9a364aafefefd6. The model is now explicit: learningViews are per anonymous device or authenticated user-device; signed-in requests only mutate their exact user-device row or claim an anonymous row; cross-device signed-in popularity dedupes by user:<id>; unsigned repeats of user-owned rows do not mutate ownership or emit analytics for the prior user. Proof: pnpm --filter @repo/backend exec vitest run convex/contents/mutations/views.test.ts convex/triggers/contents/views.test.ts passed 13/13, backend typecheck passed, root format/lint/build/doctor passed, GitHub checks are green, and current Convex dev/prod deployments added the two new learningViews indexes without deleting indexes.

@nabilfatih nabilfatih merged commit 08bdeba into main Jun 22, 2026
3 checks passed
@nabilfatih nabilfatih deleted the codex/learning-engagement-context branch June 22, 2026 21:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant