Files

102 lines
6.8 KiB
Markdown
Raw Permalink Normal View History

2026-10-07 15:30:31 +01:00
# Compact portable configuration: meguri/v2
Import / Export in Review changes now exports compact JSON. It transfers variables and generators only. Existing [v1 files](portable-config-v1.md) remain importable. No credentials, provider settings, membership, manual resources or history are exported. Import previews on the server while typing and saves only the reviewed shared draft; Sync remains a separate action. Workspace and shared-draft revision checks prevent stale application.
## Everyday structure
Variables are an object of names and ordinary JSON values. Lists are arrays; dictionaries are objects; strings, numbers and booleans need no type declarations. An email string denotes a person. Generators are an ordered array. Their outputs have readable, stable `key` names and flattened fields. Literal values need no `kind` or `value` wrapper.
```json
{
"format": "meguri/v2",
"variables": {
"on_call": ["alice@example.com", "bob@example.com"],
"projects": [
{"name":"alpha", "primary":["alice@example.com"], "secondary":["bob@example.com"]},
{"name":"beta", "primary":["bob@example.com"], "secondary":["alice@example.com"]}
]
},
"generators": [
{
"name": "Time off",
"outputs": [{
"key": "rotation",
"type": "rotation",
"name": "Time off default",
"participants": {"$var":"on_call"},
"anchor": "2026-09-28"
}]
},
{
"name": "Project owners",
"for": [{"as":"Project", "in":{"$var":"projects"}}],
"outputs": [{
"key": "primary",
"type": "priority",
"name": {"$item":["Project","name"], "suffix":" daytime primary"},
"participants": {"$item":["Project","primary"]},
"fallback": {"$output":["Time off","rotation"]}
}]
}
]
}
```
Defaults: generators are enabled; handover is 11:00 in the workspace IANA zone; rotation length is seven calendar days; repeat count/wait are zero; routes do not restrict working hours unless `working: true`. Explicit nondefaults remain in the file. Inactive editor metadata and cached values never appear. Small references and values are formatted on one line.
## Bindings
| Value | Meaning |
| --- | --- |
| `"Platform"`, `7`, `true`, `["alice@example.com"]` | Literal value |
| `{"$var":"projects"}` | Entire variable |
| `{"$var":["settings","owners","1"]}` | Variable with a nested path |
| `{"$item":["Project","primary"]}` | Field of the current iteration item |
| `{"$key":"Project"}` | Current dictionary iteration key |
| `{"$output":["Project owners","primary"]}` | Generated resource from the named output |
| `{"$lookup":["tiers",{"$item":["Project","tier"]}]}` | Dictionary lookup with a dynamic key |
| `{"$list":[{"$item":["Project","primary","1"]},"alice@example.com"]}` | List of separately evaluated bindings |
| `{"$literal":{"custom":"object"}}` | Literal object, including objects containing `$` keys |
References may add `prefix`, `suffix`, or a `path` array. Variable/item/key shorthand arrays already contain the path; do not also specify `path`. List positions are one-based strings. Dots, slashes and spaces in names remain literal: each array element is one exact path segment. There is no expression evaluation or executable code.
A generator's optional condition is `"when": [left-binding, operation, right-binding]`. `for` is an ordered array of `{"as":alias,"in":binding}` objects; nesting preserves that order.
## Escalations and routes
An escalation output uses `type: "escalation"`, `name`, optional `repeat_count`/`repeat_wait`, and `steps`:
```json
"steps": [
{"schedule":{"$output":["Project owners","primary"]}},
{"after":10, "schedule":{"$output":["Project owners","secondary"]}},
{"after":30, "team":"all"}
]
```
Each step chooses exactly one `schedule`, `person`, or `team: "all"` / `team: "random"`. `after` is minutes after alert creation (default zero). `if` defaults to `"not-acked"`; `"not-closed"` is also supported. Delays and person/schedule recipients may use any binding.
Route outputs use `type: "route"`, `name`, `escalation`, optional `working`, and `conditions`. Each condition is `[field, operation, value-binding]`; an optional final `"not"` negates it:
```json
"conditions": [
["tags", "contains", {"$item":["Project","tags"]}],
["priority", "less-than", "P3", "not"]
]
```
## Special variable types and exact dictionaries
Use `{"$date":"2026-10-01"}`, `{"$time":"09:00"}`, and `{"$duration":30}` to retain typed variable values. Use `{"$text":"literal@example.com"}` for text that looks like an email. `{"$person":"alice@example.com"}` is an explicit alternative to an email string. Unknown emails become scheduling contacts without login access; exports require a stored email for referenced people.
Ordinary JSON objects represent dictionaries in key order. When existing dictionary entry order differs from alphabetical order, or a key begins with `$`, export uses the unambiguous ordered form `{"$object":[["z",1],["a",2]]}`. This preserves iteration order and supports all existing dictionary keys. Bindings with literal person-ID comparisons use the explicit `$person` marker inside `$literal`; import resolves the email within the target workspace.
## Merge, identity and limits
Import updates matching variable/generator names (case-insensitive, trimmed), appends new inputs and retains omitted inputs. Existing generator order and route insertion position stay unchanged. An included generator replaces its full definition: removed output blocks can remove generated resources, shown before Apply.
Keep output `key` values stable when changing display names or order. Keys persist in the shared draft and do not depend on resource names. UUIDs remain internal. Variable root and dictionary-field IDs are preserved; list entries are matched first by unique value or record `name`, then by position for unmatched edits of equal-length lists. Named project reordering and field edits therefore preserve resource identity. Simultaneous renames, reorderings or edits of indistinguishable list entries can be ambiguous; inspect create/remove changes before applying. New items receive internal IDs without requiring users to author UUIDs.
Literal references to manual schedules and escalation policies still use exact target-workspace names. Import never creates manual resources. All fields, references, types, existing generation limits and provider capabilities are validated on the server. Invalid JSON, unknown fields, malformed references or stale reviews block application. Import remains limited to 1 MB of text. The preview separates input changes, generated resource changes and new email-only contacts.
`{"after":30,"team":"random"}` notifies one randomly selected member of the workspace provider team 30 minutes after alert creation if the condition still holds. The provider chooses the member; this does not sequentially notify all members and does not create a random schedule.