fix(skills,#245): lesson provenance + timestamps, drop the unparseable CSS hue - #259
Merged
Conversation
📦 Preview build readyArtifact: Built from commit 19a23a3 |
…e CSS hue The skills half of #245. The plan half (P1 `ahead` colour, P2 button labels) is NOT here — see below. **S1 — lessons lost their provenance and timestamps.** Desktop ships the full 9-field `Lesson`; `LessonVM` kept 6, dropping `provenance`, `createdAt`, `updatedAt` (epoch ms on both sides — no ISO-string trap). The pending queue therefore rendered in raw payload order with no capture age and no origin. Now parsed, sorted newest-first (stable, so equal timestamps keep payload order), and surfaced via a pure `relativeAge(at, now)` helper. Age + origin ride in the lesson spec's existing third slot, so no design-system spec change was needed. **S2 — `hue` is CSS React Native cannot parse.** Parsed and typed but never rendered, which was load-bearing in our favour: desktop values are `var(--accent)` by default and may be authored `oklch(...)`. Taking the issue's first option, it is dropped from `SkillGroupVM` rather than left as a trap for whoever first binds it to a `color` prop. The reason is recorded on the type and on the payload decoder, which passes it through as a documented deliberate ignore. **Harness:** `skills` moves from `PENDING_DOMAINS` into `DECODERS` — Layer A re-encode plus Layer B asserting lesson provenance/timestamps survive and that `skills_no_lessons` parses as null rather than an empty queue. ## Why the plan half was dropped `LivePlanBoard.tsx` — the sole target of P1 and P2 — has been DEAD CODE since 54c13fb (2026-07-25, #250), which rewrote `app/(tabs)/plan.tsx` and removed the segment strip that was its only mount point. Nothing in the repo imports it. #245 was filed 2026-07-20, five days earlier, so it cites a live surface that has not been live since. The `plan` STORE domain was not merely unmounted, it was superseded: live planning now runs on `plan_state`/`plan_event` FRAMES through `livePlan.ts` → `LivePlanContext` (mounted in `app/_layout.tsx`) → `BlueprintStageBar`, which uses a different status vocabulary (`SectionRenderStatus`), not `StageStatus`. So the `ahead` fix does not transfer — the live path needs its own audit. Tracked back on #245. Gates: `npx tsc --noEmit` clean; 529 tests pass. Refs #245 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RAPZC6xEyCrH9qSKUKLQdy
kevinthelago
force-pushed
the
245-skills-plan-polish
branch
from
July 28, 2026 21:52
5bc0011 to
3c90de0
Compare
ahead colour, honest plan labels
📦 Preview build readyArtifact: Built from commit a1de717 |
This was referenced Jul 28, 2026
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The skills half of #245. Part of #234.
S1 — lessons lost their provenance and timestamps
The desktop ships the full 9-field
Lesson;LessonVMkept 6, droppingprovenance,createdAt,updatedAt(epoch ms on both sides — the ISO-string trap that brokesecuritydoes not occur here). So the pending queue rendered in raw payload order with no capture age and no origin.Now parsed, sorted newest-first (stable, so equal timestamps keep payload order), and rendered through a pure
relativeAge(at, now)helper —nowinjected rather than read inside, so it stays testable. Age and origin ride in the lesson spec's existing third slot, so this needed nomobile.lessonItem.jsonchange.S2 —
hueis CSS React Native cannot parseParsed and typed but never rendered, which was quietly load-bearing in our favour:
parseSkillGroupsFiledefaults tovar(--accent)and authored values may beoklch(...)literals. Bind either to acolorprop and you get a crash or a silently ignored style.Taking the issue's first option: dropped from
SkillGroupVMrather than left as a trap. The reasoning is recorded on the type and on the payload decoder, which passes the field through as a documented deliberate ignore — so whoever first wants group colour finds the warning before the bug.Harness
skillsmoves fromPENDING_DOMAINSintoDECODERS: Layer A strict re-encode, plus Layer B asserting lesson provenance/timestamps survive the parse and that theskills_no_lessonsvariant yieldsnullrather than an empty queue.Why the plan half is not here
LivePlanBoard.tsx— the sole target of P1 and P2 — has had zero importers since54c13fb(2026-07-25, #250), which rewroteapp/(tabs)/plan.tsxfrom 103 lines to 18 and removed the segment strip that was its only mount point. The component file was left on disk. #245 was filed 2026-07-20, five days earlier, so it cites a surface that has not been live since.The
planstore domain was not merely unmounted — it was superseded. Live planning now runs onplan_state/plan_eventframes:livePlan.ts→LivePlanContext(mounted inapp/_layout.tsx) →BlueprintStageBar, which uses a different status vocabulary (SectionRenderStatus:in-progress/complete/ …), notStageStatus. So theaheadfix does not transfer; the live path needs its own audit against its own vocabulary.Re-scoping tracked on #245, which stays open for the plan half.
Gate
npx tsc --noEmitclean.Layer A: skills payload round-trips through the mobile model.🤖 Generated with Claude Code
https://claude.ai/code/session_01RAPZC6xEyCrH9qSKUKLQdy