Date: 2026-07-22
Source-authority audit#
| Concern | Authoritative source | Rail decision |
|---|---|---|
| Humane outcomes | libs/arete/habits recovery and friction check-ins |
Consolidate the duplicated inline unions as ARETE_HUMANE_STREAK_OUTCOMES: done, partial, skip, decline, miss. |
| Meaning | libs/arete/habits/src/check-in-status.ts |
done/partial are engaged; skip/decline receive grace; miss is neutral no-count pattern data. No status judges the user or changes a plan automatically. |
| Rail vocabulary | HumaneStreakVocabularySchema in @oshun/contracts/v10 |
Prove exact ordered equality with Arete's canonical tuple and publish that tuple in the manifest's absencePolicy.streakSemantics. The contracts layer remains dependency-inverted and does not import a feature package. |
| Current state | A user-scoped AreteProgressSource |
Require an explicit persisted check-in. Missing source data degrades through the Rail cache; the adapter never infers miss merely from absence. |
The Oshun BFF Arete adapter was inspected as well. Its streak-stat endpoint is a legacy numeric summary and its current completion facade does not expose the five-state check-in record, so neither is allowed to manufacture the Rail tile. The channel instead accepts a user-scoped explicit check-in source and strips user identity at the boundary.
Domain consolidation#
@arete/habits/check-in-status is now the one source for the five statuses,
their labels, and their streak treatments. The habits recovery and friction
models consume its exported type instead of maintaining local unions. The
subpath resolves directly to workspace TypeScript so Next, Vitest, and
TypeScript all execute the same source rather than relying on unbuilt
declaration paths.
The semantics are deliberately asymmetric:
partialkeeps contact with the plan and is engaged;skipanddeclineare choices and receive grace;missis no-count pattern data, not a penalty;- every status has
changesPlanAutomatically: falseandvisibleAsJudgement: false.
Adapter#
@oshun/v10-rail-channel-arete provides:
- a strict wellness manifest for
v1.arete, with the exact canonical outcomes in its absence policy; - a spectator-only gentle-progress tile which renders all five meanings from
@arete/habits; - strict explicit-check-in parsing, future-record rejection, normalized source timestamps, and source isolation without user identifiers;
- bounded glance and assistive text plus a contextual Arete habit deep link;
- no streak count, percentage, score, flame, countdown, urgency, autoplay, drip, micro-act, live moment, or elevation route.
The frontend treatment is a quiet record rather than a progress dashboard: the habit name and humane status are the only dominant facts, followed by one line explaining the treatment. Production registration uses the existing cardless settings directory and adds no motion or chrome.
Invariants and production registration#
Arete is shipped in the V10 production directory and added to Phase A's
post-pilot invariant set without becoming a retroactive pilot. The shared suite
pins the complete ordered vocabulary, checks punishesAbsence: false, validates
the face under the runtime no-absence-punishment policy, and proves that no live
moment can reach elevation.
Verification#
- Arete habits library/type and spec typechecks: pass.
- Arete habits lint: pass; full Vitest 252/252 passes.
- Arete channel typecheck and lint: pass; Vitest 12/12 passes, including every status, absent-source behavior, strict failures, privacy, text bounds, and real Rail-host JSON Schema binding.
- Phase A typecheck and lint: pass; invariant Vitest 31/31 passes.
- V10 web typecheck and lint: pass; Vitest 166/166 passes.
- Frozen offline filtered lockfile validation: pass.
- Production-directory Playwright: 4/4 across desktop and mobile Chromium, including automatic Axe accessibility analysis and overflow assertions.
Thread dependency#
Nyx, Tara, and Arete now all have contract-ready V1 house-channel adapters, so X-4 is complete and no longer blocks the X-3 morning Thread composition.