{"schemaVersion":1,"kind":"egghead-release-discussion","revision":"2aabf938d054ecea47738a9c383ba4cbdcc883ca2c883824e3c2c097cfa56a17","sourceRepository":"badass-courses/egghead","sourceRevision":"fab0259a0be6655307790df3cf1b73b895fc4c68","evidence":{"investigations":7,"model":"openai-codex/vega-alpha","effort":"max","mode":"static-source-synthesis","sourceFiles":172,"applicationTestsRun":false,"transactionsRun":false,"implementationAuthorized":false},"permissions":{"read":true,"write":false,"reason":"Discussion artifact; no production or implementation authorization"},"capabilities":{"discover":{"method":"GET","path":"/brief.json"},"inspect":{"targets":["decisions[].id","tasks[].id"],"mechanism":"Read this immutable document and select an exact stable ID"},"query":{"mechanism":"Filter decisions and tasks client-side; no remote query service"},"act":{"available":false,"reason":"Read-only discussion artifact"},"wait":{"available":false,"reason":"Synthesis completed; no live jobs"},"diagnose":{"claimBoundary":"Static synthesis only","gaps":["Published-package internals","Live database rows and service settings","External migration receipts","Application runtime verification"]}},"decisions":[{"id":"D1","title":"Membership catalog","recommendation":"Retain separately mapped monthly/yearly memberships initially. Consolidate to one Stripe product/two prices only if cleaner catalog administration warrants adapter, catalog, checkout and webhook compatibility work.","status":"proposed"},{"id":"D2","title":"Cancellation and payment grace","recommendation":"Default cancellation to period-end, honoring paid-through access. Define bounded failed-payment grace and recovery separately. Grace reduces accidental lockouts but permits some unpaid access; `past_due` alone is not a complete policy.","status":"proposed"},{"id":"D3","title":"Seats and invitations","recommendation":"Keep explicit owner seat claiming and allocation on acceptance. Recommend expiring, revocable, email-scoped invitations. Keep self-service shrink disabled until reconciled; support can unassign before reducing quantity. Safer capacity management costs administrative steps.","status":"proposed"},{"id":"D4","title":"Public progress privacy","recommendation":"Recommend opt-in public activity, or defer public sharing without blocking private progress. Always-public profiles simplify sharing but expose learning activity without a consent step.","status":"proposed"},{"id":"D5","title":"Identity/import continuity","recommendation":"Prove active/paid customer continuity through the existing migration owner; preserve existing Stripe subscriptions. Defer dormant-user and historical-progress imports. Smaller cutover scope means support-led long-tail recovery.","status":"proposed"},{"id":"D6","title":"Connection, writes and traffic ownership","recommendation":"Approve beta connection and each write family separately. Preserve production and beta-commerce restrictions until separately reviewed changes. Traffic/read authority, billing writers, migration writes and search indexing are distinct approvals—not one “go live” switch.","status":"proposed"}],"tasks":[{"id":"EH-R1","title":"Establish an enforceable permission matrix","ownerRole":"Runtime/DB, with Release approval","decisionAndBlocker":"D6; target credentials and permitted write families are unspecified.","status":"proposed","dependsOn":[],"acceptance":"an operation-by-runtime matrix covering approved-beta commerce denial, authorized account/progress writes, blocked DDL and Portal/webhook boundaries. `SELECT 1` alone cannot prove read-only operation.","sourceReferences":["https://github.com/badass-courses/egghead/blob/fab0259a0be6655307790df3cf1b73b895fc4c68/apps/web/src/db/local-docker.ts#L70-L178","https://github.com/badass-courses/egghead/blob/fab0259a0be6655307790df3cf1b73b895fc4c68/apps/web/src/progress/resource-progress.ts#L72-L224","https://github.com/badass-courses/egghead/blob/fab0259a0be6655307790df3cf1b73b895fc4c68/apps/web/src/app/api/route.ts"]},{"id":"EH-C1","title":"Freeze the supported catalog mapping","ownerRole":"Commerce/CourseBuilder integration","decisionAndBlocker":"D1; actual catalog rows and package internals are unavailable.","status":"proposed","dependsOn":[],"acceptance":"monthly/yearly checkout selects the intended price, amount and quantity; inactive mappings disappear; quantities 0/101 fail; sandbox/live identifiers cannot be mixed unnoticed.","sourceReferences":["https://github.com/badass-courses/egghead/blob/fab0259a0be6655307790df3cf1b73b895fc4c68/apps/web/src/subscriptions/catalog.ts","https://github.com/badass-courses/egghead/blob/fab0259a0be6655307790df3cf1b73b895fc4c68/apps/web/src/inngest/stripe-subscription.ts"]},{"id":"EH-C2","title":"Make subscription and seat state converge","ownerRole":"Subscriptions/Teams","decisionAndBlocker":"D2/D3, EH-C1 and test identities.","status":"proposed","dependsOn":["EH-C1"],"acceptance":"personal/team renewal, scheduled/immediate cancellation, failure/recovery, duplicate/out-of-order events, seat races, removal and quantity transitions produce agreed access. Concurrent/replaced checkout attempts—including session-expiry failure—must not create two payable subscriptions.","sourceReferences":["https://github.com/badass-courses/egghead/blob/fab0259a0be6655307790df3cf1b73b895fc4c68/apps/web/src/subscriptions/access.ts#L8-L139","https://github.com/badass-courses/egghead/blob/fab0259a0be6655307790df3cf1b73b895fc4c68/apps/web/src/inngest/stripe-subscription.ts#L249-L400","https://github.com/badass-courses/egghead/blob/fab0259a0be6655307790df3cf1b73b895fc4c68/apps/web/src/subscriptions/team.ts","https://github.com/badass-courses/egghead/blob/fab0259a0be6655307790df3cf1b73b895fc4c68/apps/web/src/app/team/actions.ts"]},{"id":"EH-A1","title":"Reconcile authorization predicates and paid-content classification","ownerRole":"Access/Migration","decisionAndBlocker":"D5, EH-C2; representative legacy projections are externally unavailable.","status":"proposed","dependsOn":["EH-C2"],"acceptance":"align these existing helpers around an approved cohort matrix: personal subscriber, unseated owner, seated/removed member, organization-only member, canceled legacy subscriber, lifetime, playlist/country-restricted purchase and quarantine-only user. Preserve legitimate grants and bare-`pro` denial. Known paid fixtures must not become free through missing linkage or expose usable denied playback through page/embed responses.","sourceReferences":["https://github.com/badass-courses/egghead/blob/fab0259a0be6655307790df3cf1b73b895fc4c68/apps/web/src/access/evaluate.ts","https://github.com/badass-courses/egghead/blob/fab0259a0be6655307790df3cf1b73b895fc4c68/apps/web/src/subscriptions/status.ts#L10-L51","https://github.com/badass-courses/egghead/blob/fab0259a0be6655307790df3cf1b73b895fc4c68/apps/web/src/support/readback.ts","https://github.com/badass-courses/egghead/blob/fab0259a0be6655307790df3cf1b73b895fc4c68/apps/web/src/content/lesson.ts","https://github.com/badass-courses/egghead/blob/fab0259a0be6655307790df3cf1b73b895fc4c68/apps/web/src/content/lesson-page.tsx"]},{"id":"EH-I1","title":"Prove identity continuity and token boundaries","ownerRole":"Auth/Security","decisionAndBlocker":"D3/D5; provider/package behavior and import mapping require receipts.","status":"proposed","dependsOn":[],"acceptance":"real email/OAuth callbacks retain the intended database user and access; expired/replayed magic links fail; mismatched emails cannot claim scoped invitations; revoked invitations cannot reclaim removed seats; disconnect preserves another usable sign-in method.","sourceReferences":["https://github.com/badass-courses/egghead/blob/fab0259a0be6655307790df3cf1b73b895fc4c68/apps/web/src/coursebuilder/auth-config.ts#L15-L100","https://github.com/badass-courses/egghead/blob/fab0259a0be6655307790df3cf1b73b895fc4c68/apps/web/src/subscriptions/team-invite-token.ts","https://github.com/badass-courses/egghead/blob/fab0259a0be6655307790df3cf1b73b895fc4c68/apps/web/src/profile/data.ts#L524-L568","https://github.com/badass-courses/egghead/blob/fab0259a0be6655307790df3cf1b73b895fc4c68/apps/web/src/coursebuilder/current-user.ts#L50-L130"]},{"id":"EH-L1","title":"Verify progress persistence and settle public exposure","ownerRole":"Learning/Product","decisionAndBlocker":"D4, EH-I1 and permitted account/progress writes.","status":"proposed","dependsOn":["EH-I1"],"acceptance":"complete/uncomplete persists across sessions; last-lesson/course state agrees; partial failure and empty-course cases are explicit. Private reads reject another actor. Public page, metadata and OpenGraph follow D4 and omit email/provider/purchase details. If sharing is deferred, gate public reads—not merely the copy-link button. Full public-history pagination is optional.","sourceReferences":["https://github.com/badass-courses/egghead/blob/fab0259a0be6655307790df3cf1b73b895fc4c68/apps/web/src/profile/data.ts","https://github.com/badass-courses/egghead/blob/fab0259a0be6655307790df3cf1b73b895fc4c68/apps/web/src/progress/course-progress.ts#L82-L157"]},{"id":"EH-R2","title":"Collect staged receipts and rehearse rollback","ownerRole":"Release/Operations, with Migration and Support","decisionAndBlocker":"D6; preceding acceptance receipts and external approvals.","status":"proposed","dependsOn":[],"acceptance":"Local contract/build receipts; approved-beta runtime and write-permission receipts; separately approved migration/cutover and rollback rehearsal.","sourceReferences":["https://github.com/badass-courses/egghead/blob/fab0259a0be6655307790df3cf1b73b895fc4c68/package.json","https://github.com/badass-courses/egghead/blob/fab0259a0be6655307790df3cf1b73b895fc4c68/scripts/builder-smoke.ts","https://github.com/badass-courses/egghead/blob/fab0259a0be6655307790df3cf1b73b895fc4c68/VISION.md"]}],"illustrations":{"status":"blocked","reason":"Required Eggo character guide unavailable; no substitute mascot artwork generated"},"files":{"fullAnalysis":"/full-analysis.md","article":"/"}}