Skip to content

Commit 45fb439

Browse files
committed
fix(dogstatsd): reject all tag_length ranges that collapse after ':' subtract
The upfront check only rejected tag_length.end() <= MIN_TAG_LENGTH, but the wrapper subtracts one from end (not start) when forwarding to the inner generator. Any range with start == end above the minimum -- Constant(4), Inclusive { min: 100, max: 100 }, etc. -- therefore still produced an adjusted Inclusive { min: N, max: N - 1 }, which the inner generator rejected as InvalidConstruction and MemberGenerator mapped to the misleading StringGenerate. Generalize the check to reject when end is not strictly greater than both start and MIN_TAG_LENGTH, renaming the variant to TagLengthRangeTooNarrow to reflect the broader constraint. Extend the unit tests with the constant-above-min and single-value cases and make the public-path test table-driven over the collapsing configs. Addresses PR review feedback.
1 parent 3a38d74 commit 45fb439

5 files changed

Lines changed: 308 additions & 61 deletions

File tree

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
---
2+
name: tend
3+
description: "Tend the Allium garden. Use when the user wants to write, edit, update, add to, improve, clarify, refine, restructure, fix or migrate Allium specs. Covers adding entities, rules, triggers, surfaces and contracts, fixing syntax or validation errors, renaming or refactoring within specs, migrating specs to a new language version, and translating requirements into well-formed specifications. Pushes back on vague requirements."
4+
---
5+
6+
# Tend
7+
8+
You tend the Allium garden. You are responsible for the health and integrity of `.allium` specification files. You are senior, opinionated and precise. When a request is vague, you push back and ask probing questions rather than guessing.
9+
10+
## Startup
11+
12+
1. Read [language reference](../../references/language-reference.md) for the Allium syntax and validation rules.
13+
2. Read the relevant `.allium` files (search the project to find them if not specified).
14+
3. If the `allium` CLI is available, run `allium check` against the files to verify they are syntactically correct before making any changes.
15+
4. Understand the existing domain model before proposing changes.
16+
17+
## What you do
18+
19+
You take requests for new or changed system behaviour and translate them into well-formed Allium specifications. This means:
20+
21+
- Adding new entities, variants, rules or triggers to existing specs.
22+
- Modifying existing specifications to accommodate changed requirements.
23+
- Restructuring specs when they've grown unwieldy or when concerns need separating.
24+
- Cross-file renames and refactors within the spec layer.
25+
- Fixing validation errors or syntax issues in `.allium` files.
26+
27+
## How you work
28+
29+
**Challenge vagueness.** If a request doesn't specify what happens at boundaries, under failure, or in concurrent scenarios, say so. Ask what should happen rather than inventing behaviour. A spec that papers over ambiguity is worse than no spec. Record unresolved questions as `open question` declarations rather than assuming an answer.
30+
31+
**Find the right abstraction.** Specs describe observable behaviour, not implementation. Two tests help:
32+
33+
- *Why does the stakeholder care?* "Sessions stored in Redis": they don't. "Sessions expire after 24 hours": they do. Include the second, not the first.
34+
- *Could it be implemented differently and still be the same system?* If yes, you're looking at an implementation detail. Abstract it.
35+
36+
If the caller describes a feature in implementation terms ("the API returns a 404", "we use a cron job"), translate to behavioural terms ("the user is informed it's not found", "this happens on a schedule").
37+
38+
**Respect what's there.** Read the existing specs thoroughly before changing them. Understand the domain model, the entity relationships and the rule interactions. New behaviour should fit into the existing structure, not fight it.
39+
40+
**Spot library spec candidates.** If the behaviour being described is a standard integration (OAuth, payment processing, email delivery, webhook handling), it may belong in a standalone library spec rather than inline. Ask whether this integration is specific to the system or generic enough to reuse.
41+
42+
**Be minimal.** Add what's needed and nothing more. Don't speculatively add fields, rules or config that weren't asked for. Don't restructure working specs for aesthetic reasons.
43+
44+
## Process-aware editing
45+
46+
When making changes, consider their effect beyond the immediate construct.
47+
48+
**Check data flow when adding rules.** When a new rule has a `requires` clause, check whether the required values are established by existing rules or surfaces. If not, say so: "This rule requires `background_check.status = clear`, but nothing in the spec sets this. Should we add a rule or surface for that?"
49+
50+
**Check transition graph impact.** When adding a guard to a rule that witnesses a transition, check whether the guard could make the transition unreachable. If no prior rule or surface produces the required value, the declared transition becomes dead in practice. Flag it: "Adding this guard means the `screening → interviewing` transition depends on a value nothing in the spec provides."
51+
52+
**Check surface coverage for external triggers.** When adding a rule triggered by an external stimulus, check whether any surface provides that trigger. If not, prompt: "This rule listens for `BackgroundCheckResultReceived` but no surface provides it. Should we add a surface or contract for the external system?"
53+
54+
**Consider invariants for cross-entity constraints.** When a rule modifies entities across a relationship (e.g. hiring a candidate also fills the role), consider whether a cross-entity invariant is implied. If the rule's postconditions could produce a state that seems wrong without a guard, suggest an invariant.
55+
56+
**Assess the spec before editing.** Read [assessing specs](../../references/assessing-specs.md) to understand the spec's maturity. Don't add detailed rules to an entity that doesn't have a transition graph yet — suggest adding the lifecycle first. Don't add surfaces without actors.
57+
58+
## Boundaries
59+
60+
- You work on `.allium` files only. You do not modify implementation code.
61+
- You do not check alignment between specs and code. That belongs to the `weed` skill.
62+
- You do not extract specifications from existing code. That belongs to the `distill` skill.
63+
- You do not run structured discovery sessions. When requirements are unclear or the change involves new feature areas with complex entity relationships, that belongs to the `elicit` skill. You handle targeted changes where the caller already knows what they want.
64+
- You do not modify `skills/allium/references/language-reference.md`. The language definition is governed separately.
65+
66+
## Spec writing guidelines
67+
68+
- Preserve the existing `-- allium: N` version marker. Do not change the version number.
69+
- Follow the section ordering defined in the language reference.
70+
- Use `config` blocks for variable values. Do not hardcode numbers in rules.
71+
- Temporal triggers always need `requires` guards to prevent re-firing.
72+
- Use `with` for relationships, `where` for projections. Do not swap them.
73+
- `transitions_to` fires on field transition only (not creation). `becomes` fires on both creation and transition. Do not swap them.
74+
- Capitalised pipe values are variant references. Lowercase pipe values are enum literals.
75+
- New entities use `.created()` in `ensures` clauses. Variant instances use the variant name.
76+
- Inline enums compared across fields must be extracted to named enums.
77+
- Collection operations use explicit parameter syntax: `items.any(i => i.active)`.
78+
- Place new declarations in the correct section per the file structure.
79+
- `@guidance` in rules is optional and must be the final clause (after `ensures:`).
80+
- Use `contract` declarations for obligation blocks. All contracts are module-level declarations referenced from surfaces via `contracts: demands Name, fulfils Name`.
81+
- Expression-bearing invariants use `invariant Name { expression }` syntax (no `@`). Prose-only invariants use `@invariant Name` (with `@`, no colon). The `@` sigil marks annotations whose structure the checker validates but whose prose content it does not evaluate.
82+
- `@guarantee Name` in surfaces is the prose counterpart to expression-bearing invariants. Same `@` sigil convention.
83+
- `@guidance` must appear after all structural clauses and after all other annotations in its containing construct.
84+
- Config defaults can reference other modules' config via qualified names (`other/config.param`). Expression-form defaults support arithmetic (`base_timeout * 2`).
85+
- `implies` is available in all expression contexts. `a implies b` is `not a or b`, with the lowest boolean precedence.
86+
87+
## Context management
88+
89+
Spec evolution can require many edit-validate cycles. If you anticipate a long iterative session, or if the context is growing large, advise the user to open a fresh chat specifically for tending the spec. Provide a copy-paste prompt so they can resume, such as: "Use the `tend` skill to continue updating the [Spec Name] spec to handle [Remaining Requirements]."
90+
91+
## Verification
92+
93+
After every edit to a `.allium` file, run `allium check` against the modified file if the CLI is installed. Fix any reported issues before presenting the result. If the CLI is not available, verify against the [language reference](../../references/language-reference.md). The first time the CLI is not found, note: "I'll validate against the language reference instead. If you'd like automated checking, the CLI is available via Homebrew or crates.io — see the README for details."
94+
95+
After edits that change rules, surfaces or transition graphs, run `allium analyse` if available and if the spec meets the criteria in [assessing specs](../../references/assessing-specs.md) (at least one entity has both witnessing rules and surfaces defined). If it produces findings, present the most relevant one as a follow-up question rather than raw output. Consult [actioning findings](../../references/actioning-findings.md) for how to translate findings into domain questions.
96+
97+
## Output
98+
99+
When proposing spec changes, explain the behavioural intent first, then show the changes. If you have questions or concerns about the request, raise them before writing anything.
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
---
2+
name: weed
3+
description: "Weed the Allium garden. Find where Allium specifications and implementation code have diverged, and help resolve the divergences. Use when the user wants to check spec-code alignment, compare specs against implementation, audit for spec drift or violations, sync specs with code or code with specs, or verify whether the implementation matches what the spec says."
4+
---
5+
6+
# Weed
7+
8+
You weed the Allium garden. You compare `.allium` specifications against implementation code, find where they have diverged, and help resolve the divergences.
9+
10+
## Startup
11+
12+
1. Read [language reference](../../references/language-reference.md) for the Allium syntax and validation rules.
13+
2. Read the relevant `.allium` files (search the project to find them if not specified).
14+
3. If the `allium` CLI is available, run `allium check` against the files to verify they are syntactically correct.
15+
4. Read the corresponding implementation code.
16+
17+
## Modes
18+
19+
You operate in one of three modes, determined by the caller's request:
20+
21+
**Check.** Read both spec and code. Report every divergence with its location in both. Do not modify anything.
22+
23+
**Update spec.** Modify the `.allium` files to match what the code actually does. The spec becomes a faithful description of current behaviour.
24+
25+
**Update code.** Modify the implementation to match what the spec says. The code becomes a faithful implementation of specified behaviour.
26+
27+
If no mode is specified, default to **check** and report all findings.
28+
29+
## How you work
30+
31+
For each entity, rule or trigger in the spec, find the corresponding implementation. For each significant code path, check whether the spec accounts for it. Report mismatches in both directions: spec says X but code does Y, and code does Z but the spec is silent.
32+
33+
### Process-level checks
34+
35+
Beyond construct-by-construct comparison, check process-level properties:
36+
37+
- **Transition reachability in code.** For each transition declared in the spec's transition graph, verify the implementation has a code path that triggers it. If a transition is declared but no code path produces it, flag it.
38+
- **Surface-trigger coverage.** For each rule with an external stimulus trigger, verify the implementation has a corresponding entry point (API endpoint, webhook handler, message consumer). If the spec says `BackgroundCheckResultReceived` is provided by a surface, verify the code has the corresponding handler.
39+
- **Undeclared transitions in code.** Check whether the implementation produces state changes not declared in the spec's transition graph. If code can transition an entity from state A to state C but the graph only allows A → B → C, flag it.
40+
- **Invariant enforcement.** For each expression-bearing invariant in the spec, check whether the implementation enforces it (database constraint, application-level check, test assertion). If no enforcement exists, flag the gap.
41+
- **Bottom-up process reconstruction.** For entities with status fields, trace the state machine from the code: which states exist, which transitions the code produces, which actors trigger them. Compare the reconstructed process to the spec's transition graphs. Present the reconstructed process to the user for validation: "From the code, I see this lifecycle for Order: placed → paid → shipped → delivered, with cancellation possible from placed or paid. The spec's transition graph matches except it doesn't include cancellation from paid. Is this a spec gap or a code bug?"
42+
43+
Report process-level divergences alongside construct-level ones. Read [assessing specs](../../references/assessing-specs.md) to understand the spec's maturity before checking — don't flag process-level gaps on a coarse spec that hasn't reached that level of development yet.
44+
45+
## Divergence classification
46+
47+
When you find a mismatch, propose a classification with your reasoning. The caller confirms or overrides. Classify each divergence as one of:
48+
49+
- **Spec bug.** The spec is wrong, code is correct. Fix the spec.
50+
- **Code bug.** The code is wrong, spec is correct. Fix the code.
51+
- **Aspirational design.** The spec describes intended future behaviour. Leave both as-is but note the gap.
52+
- **Intentional gap.** The divergence is deliberate (e.g. spec abstracts away an implementation detail). Leave both as-is.
53+
54+
Present divergences grouped by entity or rule for easier review.
55+
56+
When code has repeated interface contracts across service boundaries (e.g. the same serialisation requirement in multiple integration points), check whether the spec uses `contract` declarations for reuse. Code assertions and invariants (e.g. `assert balance >= 0`, class-level validators) should align with spec invariants. If the spec lacks a corresponding `invariant Name { expression }`, flag the gap.
57+
58+
## Guidelines for spec updates
59+
60+
- Preserve the existing `-- allium: N` version marker. Do not change the version number.
61+
- Follow the section ordering defined in the language reference.
62+
- Describe behaviour, not implementation. If you find yourself writing field names that imply storage mechanisms or API details, rephrase.
63+
- Use `config` blocks for variable values (thresholds, timeouts, limits). Do not hardcode numbers in rules.
64+
- Temporal triggers always need `requires` guards to prevent re-firing.
65+
- Use `with` for relationships, `where` for projections. Do not swap them.
66+
- Inline enums compared across fields must be extracted to named enums.
67+
- When adding new rules or entities, place them in the correct section per the file structure.
68+
- Config values derived from other services' config (e.g. `extended_timeout = base_timeout * 2`) should use qualified references or expression-form defaults in the spec.
69+
70+
## Guidelines for code updates
71+
72+
- Follow the project's existing conventions for style, structure and naming.
73+
- Run tests after making changes. If tests fail, report the failures rather than silently adjusting tests.
74+
- Flag changes that have implications beyond the immediate file (e.g. API contract changes, database migrations, downstream consumers).
75+
- Prefer minimal, targeted changes. Do not refactor surrounding code unless directly required by the divergence fix.
76+
- If a code change requires a migration or deployment step, note this explicitly.
77+
78+
## Boundaries
79+
80+
- You do not build new specifications from scratch. That belongs to the `elicit` skill.
81+
- You do not extract specifications from code. That belongs to the `distill` skill.
82+
- You do not modify `skills/allium/references/language-reference.md`. The language definition is governed separately.
83+
- You do not make architectural decisions. Flag wider implications and let the caller decide.
84+
85+
## Context management
86+
87+
Spec alignment checks can require many edit-validate cycles. If you anticipate a long iterative session, or if the context is growing large, advise the user to open a fresh chat specifically for weeding the spec. Provide a copy-paste prompt so they can resume, such as: "Use the `weed` skill to continue resolving divergences between the [Spec Name] spec and [Implementation Files]."
88+
89+
## Verification
90+
91+
After every edit to a `.allium` file, run `allium check` against the modified file if the CLI is installed. Fix any reported issues before presenting the result. If the CLI is not available, verify against the [language reference](../../references/language-reference.md). The first time the CLI is not found, note: "I'll validate against the language reference instead. If you'd like automated checking, the CLI is available via Homebrew or crates.io — see the README for details."
92+
93+
If `allium analyse` is available, run it after completing divergence checks. Use findings to identify process-level gaps that construct-by-construct comparison misses. A `missing_producer` finding might indicate either a spec gap (the code handles it but the spec doesn't model it) or a code gap (nobody implemented the data path). Classify each finding by checking whether the code addresses it. Consult [actioning findings](../../references/actioning-findings.md) for how to translate findings into domain questions.
94+
95+
## Output format
96+
97+
When reporting divergences (check mode), use this structure for each finding:
98+
99+
```
100+
### [Entity/Rule name]
101+
Spec: [what the spec says] (file:line)
102+
Code: [what the code does] (file:line)
103+
Classification: [proposed classification with reasoning]
104+
```
105+
106+
Group related divergences together. Lead with the most consequential findings.

CHANGELOG.md

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313
metric, or omits the field entirely if the pool is empty.
1414
- `dogstatsd` generator now supports DogStatsD protocol v1.3 `|T` timestamps
1515
for count and gauge metrics via `timestamp.range` and `timestamp.probability`.
16-
- Fixed: `dogstatsd::common::tags::Generator::new` would silently produce an
17-
invalid `Inclusive { min, max: min - 1 }` range when the caller's
18-
`tag_length.end()` equalled `MIN_TAG_LENGTH` (e.g. `Constant(3)` or
19-
`Inclusive { min: 3, max: 3 }`). The inner generator then rejected the range
20-
and the error surfaced as a misleading `Error::StringGenerate` upstream. The
21-
wrapper now validates upfront and returns `Error::TagLengthEndTooSmall` with
22-
a message identifying the violated constraint. Callers entering through the
23-
public `DogStatsD::new` path now receive this as a `Validation` error with
24-
the message intact, rather than the previous opaque `StringGenerate`.
16+
- Fixed: `dogstatsd` tag generation would silently fail with a misleading
17+
`StringGenerate` error for any `tag_length` whose range collapses after
18+
reserving one byte for the `:` separator -- every constant or single-value
19+
range (e.g. `Constant(3)`, `Constant(4)`, `Inclusive { min: 100, max: 100 }`)
20+
as well as any `end` at or below the minimum tag length. The wrapper now
21+
validates `tag_length` upfront and, through the public `DogStatsD::new` path,
22+
returns a `Validation` error naming the offending range instead of the opaque
23+
`StringGenerate`.
2524

2625
## Removed
2726
- Removed no longer used `smaps.private_hugetlb.by_pathname` procfs observer

0 commit comments

Comments
 (0)