Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions plugins/allium/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"name": "allium",
"version": "3.7.0",
"version": "3.8.0",
"description": "Velocity through clarity.",
"author": {
"name": "JUXT",
"url": "https://juxt.pro"
},
"homepage": "https://juxt.github.io/allium/",
"homepage": "https://allium-lang.org/",
"repository": "https://github.com/juxt/allium",
"license": "MIT",
"keywords": ["specification", "behaviour", "behavior", "domain-modelling", "BDD", "property-based-testing", "generative-tests"],
Expand Down
6 changes: 3 additions & 3 deletions plugins/allium/.codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"name": "allium",
"version": "3.7.0",
"version": "3.8.0",
"description": "Velocity through clarity.",
"author": {
"name": "JUXT",
"url": "https://juxt.pro"
},
"homepage": "https://juxt.github.io/allium/",
"homepage": "https://allium-lang.org/",
"repository": "https://github.com/juxt/allium",
"license": "MIT",
"keywords": [
Expand All @@ -30,7 +30,7 @@
"Write",
"Interactive"
],
"websiteURL": "https://juxt.github.io/allium/",
"websiteURL": "https://allium-lang.org/",
"defaultPrompt": [
"Draft an Allium spec for this feature.",
"Review this .allium spec for gaps.",
Expand Down
12 changes: 6 additions & 6 deletions plugins/allium/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

---

Feed your AI something healthier than Markdown. [juxt.github.io/allium](https://juxt.github.io/allium/)
Feed your AI something healthier than Markdown. [allium-lang.org](https://allium-lang.org/)

## What this is

Expand All @@ -17,8 +17,8 @@ You keep a `.allium` file alongside your code describing what the system should
Two forces feed the spec, and one loop keeps it honest against the code:

```
intent ──/elicit──► β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” ◄──/distill── existing code
(forward) β”‚ .allium spec β”‚ (backward)
intent ──/elicit──► β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” ◄──/distill── existing code
(forward) β”‚ .allium spec β”‚ (backward)
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”¬β”€β”€β”€β”€β”˜
/tend β”‚ β”‚ /weed
(edit spec) β”‚ β”‚ (reconcile with code)
Expand Down Expand Up @@ -312,9 +312,9 @@ Like its namesake, working with Allium may produce tears during the peeling, but

<a href="https://www.star-history.com/?repos=juxt%2Fallium&type=date&legend=top-left">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/image?repos=juxt/allium&type=date&theme=dark&legend=top-left" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/image?repos=juxt/allium&type=date&legend=top-left" />
<img alt="Star History Chart" src="https://api.star-history.com/image?repos=juxt/allium&type=date&legend=top-left" />
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=juxt/allium&type=date&theme=dark&legend=top-left&sealed_token=vt0GNhF_frBP9ZqhIlkjvtV23Gc_DWcj6qsQ_8KGNyUZ3DhLS12B2A_pjCYzDMdOzG7jkZaXrySjpqd8F56yde5soJlN5qM30I07Nw0xbTg78E6OABguNwYRHLk9ayL9ts7TP0Rst9Ysk7c1oD6VasbdJzyVgFUtrydXzXKqej6YxB-nbfcc42BGeWmY" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=juxt/allium&type=date&legend=top-left&sealed_token=vt0GNhF_frBP9ZqhIlkjvtV23Gc_DWcj6qsQ_8KGNyUZ3DhLS12B2A_pjCYzDMdOzG7jkZaXrySjpqd8F56yde5soJlN5qM30I07Nw0xbTg78E6OABguNwYRHLk9ayL9ts7TP0Rst9Ysk7c1oD6VasbdJzyVgFUtrydXzXKqej6YxB-nbfcc42BGeWmY" />
<img alt="Star History Chart" src="https://api.star-history.com/chart?repos=juxt/allium&type=date&legend=top-left&sealed_token=vt0GNhF_frBP9ZqhIlkjvtV23Gc_DWcj6qsQ_8KGNyUZ3DhLS12B2A_pjCYzDMdOzG7jkZaXrySjpqd8F56yde5soJlN5qM30I07Nw0xbTg78E6OABguNwYRHLk9ayL9ts7TP0Rst9Ysk7c1oD6VasbdJzyVgFUtrydXzXKqej6YxB-nbfcc42BGeWmY" />
</picture>
</a>

Expand Down
27 changes: 26 additions & 1 deletion plugins/allium/skills/propagate/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ Cross-module tests are integration tests by nature. They verify that the spec's

When exploring the codebase, note which spec obligations are already covered by existing tests. An existing integration test that exercises the happy path from event submission through to acknowledged output already covers multiple `rule_success` obligations and the end-to-end scenario.

When an existing test covers a spec obligation, reference it rather than generating a duplicate. The propagate skill's value at the integration level is verifying that coverage is complete against the spec's obligation list, identifying gaps, and generating tests to fill them. Replacing working hand-written tests with generated equivalents adds no value.
When an existing test covers a spec obligation, reference it rather than generating a duplicate. The propagate skill's value at the integration level is verifying that coverage is complete against the spec's obligation list, identifying gaps, and generating tests to fill them β€” the reconciliation step in the process below makes this check explicit. Replacing working hand-written tests with generated equivalents adds no value.

### For deferred specs

Expand All @@ -175,6 +175,7 @@ Deferred specifications are fully specified in separate files. When the target c
5. **Map constructs to code** β€” correlate spec entities/rules/surfaces with implementation classes/functions/endpoints
6. **Generate tests** β€” produce test files following the project's conventions
7. **Verify tests compile/run** β€” ensure generated tests are syntactically valid
8. **Reconcile obligations** β€” confirm every obligation maps to a covering test, and auto-cover any gaps (see [Obligation reconciliation](#obligation-reconciliation))

### Discovery checklist

Expand All @@ -201,6 +202,30 @@ When generator specs are available, use them to produce valid test data:
- For invariants, generate states that exercise boundary conditions
- For config parameters, use declared defaults unless testing overrides

### Obligation reconciliation

After generating tests, walk the full obligation list β€” from `allium plan` output or the manual derivation β€” and map each obligation to the test that covers it, whether generated this run or pre-existing. Reconciliation is silent: obligations are internal working data, so do not narrate the mapping, print the obligation list or present a coverage report while everything is on track.

For each obligation with no covering test, attempt to cover it:

1. Generate the missing test, or extend an existing test that partially covers it
2. Verify the new test compiles and runs
3. Re-check the obligation against the result

This is a mini-loop, and it needs the same guards as the outer Allium loop (see [driving the loop](../allium/references/driving-the-loop.md)):

- **Attempt cap** β€” at most 2 attempts per obligation. If the second attempt does not produce a compiling test that covers it, park the obligation.
- **No-progress cap** β€” if a full pass over the remaining gaps covers nothing new, stop; further passes will thrash.

Obligations still uncovered when a guard trips are the only part of reconciliation the user sees. Report each with a classification and a one-line reason:

- **Infrastructure gap** β€” the test needs a seam the code does not provide: no injectable clock for a temporal obligation, no integration fixture for a cross-module chain
- **Unmappable construct** β€” in a code-first flow, no implementation code correlates with the spec construct; the implementation bridge could not be built

Missing implementation is not a residue category. In a spec-first flow no code exists yet by design: write the test against the intended interface and let it fail β€” a failing test covers its obligation, and the loop's implement phase turns it green. An obligation is uncovered only when no test for it could be written at all.

Close with a single summary line: `N obligations, M covered, K uncovered`. When everything is covered that one line is the entire user-facing output of reconciliation. Silence about an individual obligation means it is covered; anything itemised needs a human decision. When propagate runs inside the Allium loop, this line feeds the loop's consolidated summary, and the loop must not treat the spec as converged while obligations remain uncovered without a reported reason.

## Interaction with other tools

- **distill** produces specs from code. Those specs feed propagate.
Expand Down
2 changes: 1 addition & 1 deletion scripts/allium-ref.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v3.7.0
v3.8.0
Loading