Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
fe011b9
chore(tooling): wire up dx-flow commit workflow with oxlint
keyobs Aug 9, 2026
decfd0b
build(spike): install vertical-spike dependencies and configure vitest
keyobs Aug 9, 2026
d6ba57a
feat(data): add FDJ EuroMillions historical draws CSV
keyobs Aug 9, 2026
1742f39
feat(domain): add Grid model with validation and Draw type
keyobs Aug 9, 2026
83164f6
feat(csv): parse the FDJ export into Draw[]
keyobs Aug 9, 2026
0df59ac
feat(domain): add FeatureExtractor and GeometryDescriptor
keyobs Aug 9, 2026
baf421e
feat(pca): project draws into SpatialEmbedding-shaped 3D coordinates
keyobs Aug 9, 2026
dc52e13
feat(spike): render the SpatialEmbedding as a bare three.js point cloud
keyobs Aug 9, 2026
ebae9be
test(e2e): add Playwright for the dev-server smoke check
keyobs Aug 9, 2026
73a635f
build(v1): install router, query, charts, sass, and testing-library
keyobs Aug 9, 2026
8be8449
feat(domain): add GeometryDistance between two GeometryDescriptors
keyobs Aug 9, 2026
c1b6697
feat(domain): add the four evaluation scores (structure/originality/t…
keyobs Aug 9, 2026
b5b26db
feat(infra): add DrawRepository backed by the FDJ CSV
keyobs Aug 9, 2026
eb514bd
feat(application): generate structurally-common/balanced/anti-share v…
keyobs Aug 9, 2026
d8ef39e
feat(app): add React Router + TanStack Query shell with the three V1 …
keyobs Aug 10, 2026
3a405d5
feat(evaluation): build the /evaluation page
keyobs Aug 10, 2026
11be58e
feat(draws): build the /draws page
keyobs Aug 10, 2026
240ff36
feat(geometry): build the /geometry page
keyobs Aug 10, 2026
fba4079
test(pages): add render-without-crash and interaction tests for the t…
keyobs Aug 10, 2026
f90cf5b
fix(build): make the "check" script actually type-check the project
keyobs Aug 10, 2026
a4ed8d7
fix(tooling): fix the same broken tsc invocation in the pre-commit hook
keyobs Aug 10, 2026
5b218a9
test(e2e): add Playwright E2E spec for input -> evaluation -> geometry
keyobs Aug 10, 2026
0e2bd40
feat(domain): add seeded PRNG for reproducible strategies and Monte C…
keyobs Aug 10, 2026
8f14882
feat(domain): add Strategy model and proposeGrid
keyobs Aug 10, 2026
0181586
feat(domain): add EuroMillions prize-rank lookup
keyobs Aug 10, 2026
bc63a1e
feat(domain): add the walk-forward StrategyBacktester
keyobs Aug 10, 2026
5cf45b8
feat(domain): add baselines, Monte Carlo comparison, and a real perf fix
keyobs Aug 10, 2026
197681c
feat(domain): add train/validation/test date-range split and overfitt…
keyobs Aug 10, 2026
1ddaa7f
feat(application): compose Strategy + backtester + baselines into Exp…
keyobs Aug 10, 2026
0f73e13
feat(laboratory): build the /laboratory page
keyobs Aug 10, 2026
ddc7f70
test(laboratory): add component render/interaction test and E2E spec
keyobs Aug 10, 2026
65b3633
fix(evaluation): replace type=number grid inputs with a proper digit-…
keyobs Aug 10, 2026
5dfb856
style(design): dark-first design pass on nav, /evaluation, /draws, /l…
keyobs Aug 10, 2026
49911f4
feat(discovery): add train-only normalization with traceable exclusions
keyobs Aug 10, 2026
a02acb7
feat(discovery): upgrade PCA to expose explained variance and feature…
keyobs Aug 10, 2026
3a488fb
feat(discovery): add K-Means clustering with silhouette k-selection a…
keyobs Aug 10, 2026
9738cd0
feat(discovery): add k-NN density and outlier scoring
keyobs Aug 11, 2026
711de96
feat(discovery): add synthetic null-hypothesis draw generator
keyobs Aug 11, 2026
21e7e93
feat(discovery): compose the real DiscoveryModel.fit() -> SpatialEmbe…
keyobs Aug 11, 2026
4020e37
feat(discovery): build the /discovery page (Carte + Familles views)
keyobs Aug 11, 2026
de8e4ca
test(discovery): add render/interaction test for the /discovery page
keyobs Aug 11, 2026
ad4cd02
fix(evaluation): live input validation, plain-language descriptions, …
keyobs Aug 11, 2026
f3249f1
fix(evaluation): flag duplicate numbers/stars red on the second occur…
keyobs Aug 11, 2026
57f872c
fix(geometry): reference grid banner, chart descriptions, highlighted…
keyobs Aug 11, 2026
a099679
fix(geometry): link reference grid to /evaluation input, add source s…
keyobs Aug 12, 2026
02cada0
chore(agents): stop ignoring .claude and .agents so agent tooling is …
keyobs Aug 12, 2026
f783ac5
feat(agents): add architect subagent
keyobs Aug 12, 2026
5c88fb7
feat(agents): add test-strategist subagent
keyobs Aug 12, 2026
90444d3
feat(agents): add quality-reviewer subagent
keyobs Aug 13, 2026
50a1b37
feat(agents): add feature workflow doc
keyobs Aug 13, 2026
fceff87
feat(ci): gate main/develop with GitHub Actions, add deploy-troublesh…
keyobs Aug 13, 2026
fa88173
feat(ci): deploy develop to GitHub Pages, keep Vercel for main
keyobs Aug 13, 2026
1905676
fix(ci): authenticate the private registry, pin Node 24, unbreak Node…
keyobs Aug 13, 2026
1b4e166
fix(ci): use GITHUB_TOKEN for the packages registry, not a manual secret
keyobs Aug 13, 2026
8eecd81
fix(ci): stop double-running tests on develop pushes
keyobs Aug 13, 2026
314c723
fix(ci): grant packages: read on ci.yml too
keyobs Aug 13, 2026
c0cbeaf
fix(ci): drop the redundant push:main trigger on ci.yml
keyobs Aug 13, 2026
2e4a425
fix(draws): resolve the CSV path against the deployed base, not the d…
keyobs Aug 13, 2026
33a5e39
feat(evaluation): flag whether a grid already appeared in the histori…
keyobs Aug 13, 2026
afe626d
feat(evaluation): also flag when the 5 numbers already came out, star…
keyobs Aug 13, 2026
4a2658c
feat(app): make the top navbar sticky on scroll
keyobs Aug 13, 2026
0813d90
feat(evaluation): restore the last evaluated grid on page load
keyobs Aug 13, 2026
82290c8
feat(agents): add release-manager subagent
keyobs Aug 13, 2026
6d4a90d
doc(readme): rewrite in English, document architecture and agent tooling
keyobs Aug 13, 2026
8abc2ce
doc(changelog): add CHANGELOG.md for the 0.1.0 release
keyobs Aug 14, 2026
cfa5f5a
fix(agents): tighten release-manager's brevity and self-verification
keyobs Aug 14, 2026
a4f839d
chore(skills): sync skills-lock.json with the installed skills
keyobs Aug 14, 2026
1d2494b
chore(release): 0.1.0
keyobs Aug 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .agents/skills/domain-modeling/ADR-FORMAT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# ADR Format

ADRs live in `docs/adr/` and use sequential numbering: `0001-slug.md`, `0002-slug.md`, etc.

Create the `docs/adr/` directory lazily — only when the first ADR is needed.

## Template

```md
# {Short title of the decision}

{1-3 sentences: what's the context, what did we decide, and why.}
```

That's it. An ADR can be a single paragraph. The value is in recording *that* a decision was made and *why* — not in filling out sections.

## Optional sections

Only include these when they add genuine value. Most ADRs won't need them.

- **Status** frontmatter (`proposed | accepted | deprecated | superseded by ADR-NNNN`) — useful when decisions are revisited
- **Considered Options** — only when the rejected alternatives are worth remembering
- **Consequences** — only when non-obvious downstream effects need to be called out

## Numbering

Scan `docs/adr/` for the highest existing number and increment by one.

## When to offer an ADR

All three of these must be true:

1. **Hard to reverse** — the cost of changing your mind later is meaningful
2. **Surprising without context** — a future reader will look at the code and wonder "why on earth did they do it this way?"
3. **The result of a real trade-off** — there were genuine alternatives and you picked one for specific reasons

If a decision is easy to reverse, skip it — you'll just reverse it. If it's not surprising, nobody will wonder why. If there was no real alternative, there's nothing to record beyond "we did the obvious thing."

### What qualifies

- **Architectural shape.** "We're using a monorepo." "The write model is event-sourced, the read model is projected into Postgres."
- **Integration patterns between contexts.** "Ordering and Billing communicate via domain events, not synchronous HTTP."
- **Technology choices that carry lock-in.** Database, message bus, auth provider, deployment target. Not every library — just the ones that would take a quarter to swap out.
- **Boundary and scope decisions.** "Customer data is owned by the Customer context; other contexts reference it by ID only." The explicit no-s are as valuable as the yes-s.
- **Deliberate deviations from the obvious path.** "We're using manual SQL instead of an ORM because X." Anything where a reasonable reader would assume the opposite. These stop the next engineer from "fixing" something that was deliberate.
- **Constraints not visible in the code.** "We can't use AWS because of compliance requirements." "Response times must be under 200ms because of the partner API contract."
- **Rejected alternatives when the rejection is non-obvious.** If you considered GraphQL and picked REST for subtle reasons, record it — otherwise someone will suggest GraphQL again in six months.
60 changes: 60 additions & 0 deletions .agents/skills/domain-modeling/CONTEXT-FORMAT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# CONTEXT.md Format

## Structure

```md
# {Context Name}

{One or two sentence description of what this context is and why it exists.}

## Language

**Order**:
{A one or two sentence description of the term}
_Avoid_: Purchase, transaction

**Invoice**:
A request for payment sent to a customer after delivery.
_Avoid_: Bill, payment request

**Customer**:
A person or organization that places orders.
_Avoid_: Client, buyer, account
```

## Rules

- **Be opinionated.** When multiple words exist for the same concept, pick the best one and list the others under `_Avoid_`.
- **Keep definitions tight.** One or two sentences max. Define what it IS, not what it does.
- **Only include terms specific to this project's context.** General programming concepts (timeouts, error types, utility patterns) don't belong even if the project uses them extensively. Before adding a term, ask: is this a concept unique to this context, or a general programming concept? Only the former belongs.
- **Group terms under subheadings** when natural clusters emerge. If all terms belong to a single cohesive area, a flat list is fine.

## Single vs multi-context repos

**Single context (most repos):** One `CONTEXT.md` at the repo root.

**Multiple contexts:** A `CONTEXT-MAP.md` at the repo root lists the contexts, where they live, and how they relate to each other:

```md
# Context Map

## Contexts

- [Ordering](./src/ordering/CONTEXT.md) — receives and tracks customer orders
- [Billing](./src/billing/CONTEXT.md) — generates invoices and processes payments
- [Fulfillment](./src/fulfillment/CONTEXT.md) — manages warehouse picking and shipping

## Relationships

- **Ordering → Fulfillment**: Ordering emits `OrderPlaced` events; Fulfillment consumes them to start picking
- **Fulfillment → Billing**: Fulfillment emits `ShipmentDispatched` events; Billing consumes them to generate invoices
- **Ordering ↔ Billing**: Shared types for `CustomerId` and `Money`
```

The skill infers which structure applies:

- If `CONTEXT-MAP.md` exists, read it to find contexts
- If only a root `CONTEXT.md` exists, single context
- If neither exists, create a root `CONTEXT.md` lazily when the first term is resolved

When multiple contexts exist, infer which one the current topic relates to. If unclear, ask.
74 changes: 74 additions & 0 deletions .agents/skills/domain-modeling/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---
name: domain-modeling
description: Build and sharpen a project's domain model. Use when the user wants to pin down domain terminology or a ubiquitous language, record an architectural decision, or when another skill needs to maintain the domain model.
---

# Domain Modeling

Actively build and sharpen the project's domain model as you design. This is the *active* discipline — challenging terms, inventing edge-case scenarios, and writing the glossary and decisions down the moment they crystallise. (Merely *reading* `CONTEXT.md` for vocabulary is not this skill — that's a one-line habit any skill can do. This skill is for when you're changing the model, not just consuming it.)

## File structure

Most repos have a single context:

```
/
├── CONTEXT.md
├── docs/
│ └── adr/
│ ├── 0001-event-sourced-orders.md
│ └── 0002-postgres-for-write-model.md
└── src/
```

If a `CONTEXT-MAP.md` exists at the root, the repo has multiple contexts. The map points to where each one lives:

```
/
├── CONTEXT-MAP.md
├── docs/
│ └── adr/ ← system-wide decisions
├── src/
│ ├── ordering/
│ │ ├── CONTEXT.md
│ │ └── docs/adr/ ← context-specific decisions
│ └── billing/
│ ├── CONTEXT.md
│ └── docs/adr/
```

Create files lazily — only when you have something to write. If no `CONTEXT.md` exists, create one when the first term is resolved. If no `docs/adr/` exists, create it when the first ADR is needed.

## During the session

### Challenge against the glossary

When the user uses a term that conflicts with the existing language in `CONTEXT.md`, call it out immediately. "Your glossary defines 'cancellation' as X, but you seem to mean Y — which is it?"

### Sharpen fuzzy language

When the user uses vague or overloaded terms, propose a precise canonical term. "You're saying 'account' — do you mean the Customer or the User? Those are different things."

### Discuss concrete scenarios

When domain relationships are being discussed, stress-test them with specific scenarios. Invent scenarios that probe edge cases and force the user to be precise about the boundaries between concepts.

### Cross-reference with code

When the user states how something works, check whether the code agrees. If you find a contradiction, surface it: "Your code cancels entire Orders, but you just said partial cancellation is possible — which is right?"

### Update CONTEXT.md inline

When a term is resolved, update `CONTEXT.md` right there. Don't batch these up — capture them as they happen. Use the format in [CONTEXT-FORMAT.md](./CONTEXT-FORMAT.md).

`CONTEXT.md` should be totally devoid of implementation details. Do not treat `CONTEXT.md` as a spec, a scratch pad, or a repository for implementation decisions. It is a glossary and nothing else.

### Offer ADRs sparingly

Only offer to create an ADR when all three are true:

1. **Hard to reverse** — the cost of changing your mind later is meaningful
2. **Surprising without context** — a future reader will wonder "why did they do it this way?"
3. **The result of a real trade-off** — there were genuine alternatives and you picked one for specific reasons

If any of the three is missing, skip the ADR. Use the format in [ADR-FORMAT.md](./ADR-FORMAT.md).
3 changes: 3 additions & 0 deletions .agents/skills/domain-modeling/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
interface:
display_name: "Domain Modeling"
short_description: "Build and sharpen a domain model"
7 changes: 7 additions & 0 deletions .agents/skills/grill-me/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
name: grill-me
description: A relentless interview to sharpen a plan or design.
disable-model-invocation: true
---

Run a `/grilling` session.
5 changes: 5 additions & 0 deletions .agents/skills/grill-me/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
interface:
display_name: "Grill Me"
short_description: "Sharpen a plan through interview"
policy:
allow_implicit_invocation: false
7 changes: 7 additions & 0 deletions .agents/skills/grill-with-docs/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
name: grill-with-docs
description: A relentless interview to sharpen a plan or design, which also creates docs (ADR's and glossary) as we go.
disable-model-invocation: true
---

Run a `/grilling` session, using the `/domain-modeling` skill.
5 changes: 5 additions & 0 deletions .agents/skills/grill-with-docs/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
interface:
display_name: "Grill with Docs"
short_description: "Grill a design and write its docs"
policy:
allow_implicit_invocation: false
22 changes: 22 additions & 0 deletions .agents/skills/grilling/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
name: grilling
description: Grill the user relentlessly about a plan, decision, or idea. Use when the user wants to stress-test their thinking, or uses any 'grill' trigger phrases.
---

Interview the user relentlessly until you reach a shared understanding. Map this as a **design tree**: every decision branches into the decisions that hang off it.

Work the tree in **rounds**. The **frontier** is every decision whose prerequisites are already settled — the questions you can ask _now_ without guessing at answers you haven't heard yet. Ask the whole frontier in one round: number each question and give your recommended answer. Then wait for the user's answers before the next round.

Each question should be formatted like so:

```
❓ **Q1** - **<question title>**: <question body, might be multiple paragraphs, including multiple choices>

➡️ <your recommended answer>
```

Each round the user answers reshapes the tree — settled decisions push the frontier outward and unblock questions that depended on them. Recompute the frontier and ask the next round. A question whose answer depends on another question still open in this round belongs to a _later_ round, not this one.

Finding _facts_ is your job, never the user's. When a frontier question needs a fact from the environment (filesystem, tools, etc.), dispatch a sub-agent to find it — don't ask the user for anything you could look up yourself. Don't block on it: a running exploration is an unsettled prerequisite, so only the questions downstream of it wait for the sub-agent to report — ask the rest of the frontier now. The _decisions_ are the user's — put each to them and wait.

The session is done when the frontier is empty: every branch of the design tree visited, nothing left silently assumed. Do not act on it until the user confirms you have reached a shared understanding.
3 changes: 3 additions & 0 deletions .agents/skills/grilling/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
interface:
display_name: "Grilling"
short_description: "Stress-test thinking a round of questions at a time"
39 changes: 39 additions & 0 deletions .agents/workflows/feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Feature workflow

Entry test: if you can already name every file the change touches, and none of them are imported by more than the one feature you're changing, go straight to step 4. Otherwise — or if you're not sure — start at step 1. That's the same bar `CLAUDE.md` sets ("non trivial ou ambigu"), made checkable: naming the files is easy to fake from memory, so the test is really "did you grep to confirm it," not "does it feel obvious."

## 1. Plan

Hand the request to `architect`. It explores the real codebase before proposing anything, reaches for the `domain-modeling` skill itself when domain vocabulary is involved (see `CONTEXT.md`), and stops at a plan — no code. It states defaults for easily-reversible choices and only raises blocking questions for the ones that are hard to reverse or genuinely ambiguous.

## 2. Challenge

Run `grill-me` against the plan. Resolve every blocking question it raises before moving on.

## 3. Validate with the human

Per this repo's own process rule (`CLAUDE.md` → "Process avant tout travail de code non trivial ou ambigu"), get explicit confirmation of the plan — including the precise file list — before writing code. `architect` treats a decision as settled only once you've confirmed it in conversation, not by default; this step is where that confirmation actually happens.

## 4. Implement

Implement the approved plan incrementally. Read a file's current state before editing it — never assume session memory is up to date (`CLAUDE.md`).

## 5. Test strategy

Ask `test-strategist` for a prioritized list of what's actually worth testing for this diff — anchored on this repo's own conventions and named scientific invariants, not generic advice. Write the tests it identifies as valuable; skip the ones it explicitly says aren't.

## 6. Quality review

Run `quality-reviewer` against the final diff. It checks against `CLAUDE.md`'s documented conventions specifically (component style, naming, import order, domain purity, `data-testid` patterns) — it doesn't hunt bugs. Also run `/code-review` when the diff touches code shared across features, external I/O, or anything else hard to reverse; a single-feature change with no cross-cutting reach is already covered by `quality-reviewer` + `test-strategist` alone.

## 7. Validate

Run:
- `pnpm check`
- `pnpm lint`
- `pnpm test:run`
- `pnpm build`

## 8. Record the decision, if it earned one

If `architect` or `quality-reviewer` flagged the change as ADR-worthy (hard to reverse, surprising without context, a real trade-off), write the ADR now that it's actually settled — via the `domain-modeling` skill, following `ADR-FORMAT.md`. Don't write it earlier: an ADR records a decision, not the deliberation that led to it.
Loading