@jaimevalasek/aioson 1.9.2 → 1.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +206 -0
- package/README.md +44 -1
- package/package.json +1 -1
- package/src/cli.js +45 -1
- package/src/commands/op-capture.js +146 -0
- package/src/commands/op-forget.js +54 -0
- package/src/commands/op-identity.js +145 -0
- package/src/commands/op-list.js +105 -0
- package/src/commands/op-migrate.js +158 -0
- package/src/commands/op-promote.js +66 -0
- package/src/commands/op-reinforce.js +73 -0
- package/src/commands/op-show.js +71 -0
- package/src/commands/op-stubs.js +67 -0
- package/src/commands/preflight.js +6 -2
- package/src/commands/runtime.js +151 -0
- package/src/commands/state-save.js +61 -0
- package/src/commands/sync-agents-preflight.js +117 -3
- package/src/commands/workflow-next.js +64 -0
- package/src/handoff-contract.js +25 -0
- package/src/lib/agent-semantic-diff.js +199 -0
- package/src/operator-memory/conflict.js +202 -0
- package/src/operator-memory/decay.js +157 -0
- package/src/operator-memory/decision.js +274 -0
- package/src/operator-memory/identity.js +109 -0
- package/src/operator-memory/index-md.js +170 -0
- package/src/operator-memory/loader.js +106 -0
- package/src/operator-memory/proposal.js +179 -0
- package/src/operator-memory/prune.js +81 -0
- package/src/operator-memory/slug.js +90 -0
- package/src/operator-memory/storage.js +121 -0
- package/src/preflight-engine.js +91 -1
- package/template/.aioson/agents/dev.md +1 -1
- package/template/.aioson/agents/deyvin.md +3 -3
- package/template/.aioson/agents/manifests/pm.manifest.json +2 -1
- package/template/.aioson/agents/neo.md +1 -1
- package/template/.aioson/agents/orchestrator.md +4 -3
- package/template/.aioson/agents/pm.md +58 -6
- package/template/.aioson/agents/product.md +1 -1
- package/template/.aioson/agents/setup.md +1 -1
- package/template/.aioson/docs/deyvin/pair-execution.md +1 -1
- package/template/.aioson/skills/process/aioson-spec-driven/references/artifact-map.md +2 -2
- package/template/.aioson/skills/process/decision-presentation/SKILL.md +9 -0
- package/template/AGENTS.md +23 -0
- package/template/CLAUDE.md +23 -0
- package/template/agents/_shared/memory-capture-directive.md +115 -0
|
@@ -26,8 +26,9 @@ Loaded rules, design docs, and design governance override the default convention
|
|
|
26
26
|
Maximum 2 pages. If it exceeds that, you are doing more than necessary. Cut ruthlessly.
|
|
27
27
|
|
|
28
28
|
## When to use
|
|
29
|
-
- **MEDIUM** projects: required, runs after `@architect` and `@ux-ui`.
|
|
30
|
-
- **
|
|
29
|
+
- **MEDIUM** projects: required, runs after `@architect` and `@ux-ui`. `@pm` is the canonical owner of the initial `implementation-plan-{slug}.md`.
|
|
30
|
+
- **SMALL** projects: optional — activate if user explicitly asks for delivery planning.
|
|
31
|
+
- **MICRO** projects: skip — `@dev` reads context and architecture directly. Do not produce an implementation plan for MICRO.
|
|
31
32
|
|
|
32
33
|
## Required input
|
|
33
34
|
- `.aioson/context/project.context.md`
|
|
@@ -68,11 +69,62 @@ For existing codebases:
|
|
|
68
69
|
- `discovery.md` may have been generated either by `scan:project --with-llm` or by `@analyst` from local scan artifacts.
|
|
69
70
|
- If `discovery.md` is missing but local scan artifacts exist, do not prioritize directly from raw code maps. Route through `@analyst` first, then continue once discovery is consolidated.
|
|
70
71
|
|
|
71
|
-
##
|
|
72
|
+
## MEDIUM implementation plan (mandatory output for MEDIUM)
|
|
72
73
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
For MEDIUM features, `@pm` MUST produce `implementation-plan-{slug}.md` in `.aioson/context/`. This is Gate C.
|
|
75
|
+
|
|
76
|
+
Structure:
|
|
77
|
+
```markdown
|
|
78
|
+
---
|
|
79
|
+
feature: {slug}
|
|
80
|
+
status: approved
|
|
81
|
+
created_by: pm
|
|
82
|
+
created_at: {ISO date}
|
|
83
|
+
classification: MEDIUM
|
|
84
|
+
gate: C
|
|
85
|
+
gate_status: approved
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
# Implementation Plan — {Feature Name}
|
|
89
|
+
|
|
90
|
+
## Gate C Summary
|
|
91
|
+
[Why Gate C is approved — prerequisites satisfied]
|
|
92
|
+
|
|
93
|
+
## Required Context Package
|
|
94
|
+
[Ordered list of files @dev must read]
|
|
95
|
+
|
|
96
|
+
## Pre-Taken Decisions
|
|
97
|
+
[Decisions already made — @dev does not re-discuss these]
|
|
98
|
+
|
|
99
|
+
## Execution Sequence
|
|
100
|
+
| Phase | Scope | Primary files | Done criteria |
|
|
101
|
+
|---|---|---|---|
|
|
102
|
+
| 1 | ... | ... | ... |
|
|
103
|
+
|
|
104
|
+
## Checkpoints
|
|
105
|
+
[After each phase, what @dev must update]
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
After writing the plan, always close Gate C:
|
|
109
|
+
```
|
|
110
|
+
aioson gate:approve . --feature={slug} --gate=C
|
|
111
|
+
```
|
|
112
|
+
Or manually set `gate_plan: approved` in `spec-{slug}.md`.
|
|
113
|
+
|
|
114
|
+
**Handoff:**
|
|
115
|
+
```
|
|
116
|
+
Implementation plan written: .aioson/context/implementation-plan-{slug}.md
|
|
117
|
+
Gate C: approved
|
|
118
|
+
Next agent: @orchestrator (MEDIUM) or @dev (SMALL, user confirmed)
|
|
119
|
+
Action: /orchestrator or /dev
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Non-MEDIUM handoff reality
|
|
123
|
+
|
|
124
|
+
For non-MEDIUM projects or when the user activates `@pm` for enrichment only:
|
|
125
|
+
- Enrich the existing PRD in place.
|
|
126
|
+
- Do not produce `implementation-plan-{slug}.md` unless explicitly requested.
|
|
127
|
+
- If the feature is MEDIUM and missing a plan, inform the user and offer to produce it.
|
|
76
128
|
|
|
77
129
|
## Output contract
|
|
78
130
|
Update the same PRD file you read (`prd.md` or `prd-{slug}.md`) in place. Never replace it with a shorter template and never delete sections that already exist.
|
|
@@ -341,7 +341,7 @@ If a question is outside product scope, acknowledge it briefly and redirect: "Th
|
|
|
341
341
|
|
|
342
342
|
## Hard constraints
|
|
343
343
|
- Use `interaction_language` (fallback: `conversation_language`) from project context for all interaction and output.
|
|
344
|
-
- Never present multiple open questions in one turn when `profile=creator` (or absent/auto).
|
|
344
|
+
- Never present multiple open questions in one turn when `profile=creator` (or absent/auto). When a real decision requires user input, use `AskUserQuestion` with explicit `(Recomendado)` marker on the first option, plain-language `why`, and `Pausar / quero pensar` non-default option. Never fire `AskUserQuestion` on agent activation without a stated task — see decision-presentation Rule 7.
|
|
345
345
|
- Never produce a PRD section you haven't actually discussed — write "TBD" instead.
|
|
346
346
|
- Keep PRD files focused: if a section is growing beyond 5 bullet points, summarize.
|
|
347
347
|
- Always run the integrity check before starting a feature conversation — never skip it.
|
|
@@ -247,7 +247,7 @@ Respect existing conventions — do not suggest replacing team standards.
|
|
|
247
247
|
|
|
248
248
|
## Hard constraints
|
|
249
249
|
- Never silently default `project_type`, `profile`, `classification`, `interaction_language`, or `conversation_language`.
|
|
250
|
-
- Never present multiple open questions in one turn when `profile=creator` (or absent/auto).
|
|
250
|
+
- Never present multiple open questions in one turn when `profile=creator` (or absent/auto). When a real decision requires user input, use `AskUserQuestion` with explicit `(Recomendado)` marker on the first option, plain-language `why`, and `Pausar / quero pensar` non-default option. Never fire `AskUserQuestion` on agent activation without a stated task — see decision-presentation Rule 7.
|
|
251
251
|
- If answers are partial, ask follow-up questions until required fields are complete.
|
|
252
252
|
- If any assumption is made, ask explicit confirmation before writing the file.
|
|
253
253
|
|
|
@@ -9,7 +9,7 @@ Load this module when `@deyvin` is about to inspect, explain, fix, or implement
|
|
|
9
9
|
## Pair working style
|
|
10
10
|
|
|
11
11
|
- summarize the latest confirmed context first
|
|
12
|
-
-
|
|
12
|
+
- if the user has not stated a task, summarize the context and wait — never fabricate `AskUserQuestion` options just because the agent loaded (see decision-presentation Rule 7)
|
|
13
13
|
- propose the smallest sensible next step
|
|
14
14
|
- implement, inspect, or fix one small batch at a time
|
|
15
15
|
- validate before moving on
|
|
@@ -11,7 +11,7 @@ prd*.md
|
|
|
11
11
|
→ spec-{slug}.md (feature memory — @analyst seeds, @dev fills)
|
|
12
12
|
→ architecture.md (tech decisions — @architect)
|
|
13
13
|
→ design-doc*.md (scope-specific decisions — @architect)
|
|
14
|
-
→ implementation-plan-{slug}.md (execution sequence — @
|
|
14
|
+
→ implementation-plan-{slug}.md (execution sequence — @pm for MEDIUM, AC-SDLC-15)
|
|
15
15
|
→ spec-{slug}.md (updated) (living state during execution — @dev)
|
|
16
16
|
```
|
|
17
17
|
|
|
@@ -28,7 +28,7 @@ prd*.md
|
|
|
28
28
|
| `spec.md` | @dev | @dev | @dev, @deyvin |
|
|
29
29
|
| `architecture.md` | @architect | — | @dev, @ux-ui |
|
|
30
30
|
| `design-doc*.md` | @architect | — | @dev, @ux-ui |
|
|
31
|
-
| `implementation-plan-{slug}.md` | @
|
|
31
|
+
| `implementation-plan-{slug}.md` | @pm (MEDIUM, AC-SDLC-15) | — | @dev, @deyvin, @orchestrator |
|
|
32
32
|
|
|
33
33
|
## Naming conventions
|
|
34
34
|
|
|
@@ -56,6 +56,15 @@ Every `AskUserQuestion` in creator mode includes an option labeled "Pausar / que
|
|
|
56
56
|
2. Add a free-form option labeled "Other / Conte com suas palavras" as the last option.
|
|
57
57
|
3. If the user picks "Other", the agent synthesizes the free-form answer into one of the known alternatives internally.
|
|
58
58
|
|
|
59
|
+
### Rule 7 — No questions without a decision to make
|
|
60
|
+
|
|
61
|
+
Never emit `AskUserQuestion` (or numbered batches) just because an agent activated. A question requires a *real* decision the user must make — a fork the work cannot proceed past without their input. When an agent loads without a stated task and no active feature requires continuation:
|
|
62
|
+
|
|
63
|
+
1. Provide a brief informational summary drawn from already-loaded context (active feature, last gate, blockers, next recommendation)
|
|
64
|
+
2. Stop and wait for the user to direct
|
|
65
|
+
|
|
66
|
+
Fabricated multi-choice questions waste attention, invite arbitrary implementation paths, and corrode trust in the framework.
|
|
67
|
+
|
|
59
68
|
## Loading order
|
|
60
69
|
|
|
61
70
|
1. Agent kernel preflight loads this `SKILL.md`.
|
package/template/AGENTS.md
CHANGED
|
@@ -9,6 +9,29 @@ You operate as AIOSON — an AI development squad with specialized agents.
|
|
|
9
9
|
- If present: read it before any action
|
|
10
10
|
3. If `.aioson/rules/` contains `.md` files, note silently that project rules are active — each agent will load applicable rules automatically via its "Project rules, docs & design docs" section. Do not alarm if the directory is absent or empty.
|
|
11
11
|
|
|
12
|
+
## Memory loading
|
|
13
|
+
|
|
14
|
+
Default **ON** in v1.15.0+. Opt out via `AIOSON_OPERATOR_MEMORY=false`.
|
|
15
|
+
|
|
16
|
+
When enabled (default):
|
|
17
|
+
|
|
18
|
+
1. Read `~/.aioson/operators/{sha256(git-email)[0..16]}/MEMORY.md` if it exists.
|
|
19
|
+
2. For decisions whose title or signal_type matches the current task description: lazy-load `decisions/{slug}.md` from the same identity directory.
|
|
20
|
+
3. Apply each loaded decision without re-asking the user — they were captured precisely so this conversation does not repeat past decisions.
|
|
21
|
+
4. If a project rule in `.aioson/rules/` conflicts with a loaded decision, the project rule wins. Surface the warning emitted by the operator-memory layer to stderr; do not silently override.
|
|
22
|
+
|
|
23
|
+
If `AIOSON_OPERATOR_MEMORY=false` is set: skip silently. Backward compatible.
|
|
24
|
+
|
|
25
|
+
## Memory capture
|
|
26
|
+
|
|
27
|
+
While conversing, watch for the 4 standing-decision signals defined in `template/agents/_shared/memory-capture-directive.md` (authorization, exclusion, correction, confirmation 2x+). When you detect one, emit:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
aioson op:capture --signal=<type> --quote="<verbatim>" --proposal="<paraphrase>" --source-agent=<self>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Capture is best-effort — do not crash, retry, or surface failures to the user. The storage layer enforces the 2x promotion threshold and emits the 1-line audit on promotion.
|
|
34
|
+
|
|
12
35
|
## How to invoke agents
|
|
13
36
|
|
|
14
37
|
**Option 1 — @ file include (Codex v0.110+):**
|
package/template/CLAUDE.md
CHANGED
|
@@ -9,6 +9,29 @@ You operate as AIOSON.
|
|
|
9
9
|
- If present: read it before any action
|
|
10
10
|
3. If `.aioson/rules/` contains `.md` files, note silently that project rules are active — each agent will load applicable rules automatically via its "Project rules, docs & design docs" section. Do not alarm if the directory is absent or empty.
|
|
11
11
|
|
|
12
|
+
## Memory loading
|
|
13
|
+
|
|
14
|
+
Default **ON** in v1.15.0+. Opt out via `AIOSON_OPERATOR_MEMORY=false`.
|
|
15
|
+
|
|
16
|
+
When enabled (default):
|
|
17
|
+
|
|
18
|
+
1. Read `~/.aioson/operators/{sha256(git-email)[0..16]}/MEMORY.md` if it exists.
|
|
19
|
+
2. For decisions whose title or signal_type matches the current task description: lazy-load `decisions/{slug}.md` from the same identity directory.
|
|
20
|
+
3. Apply each loaded decision without re-asking the user — they were captured precisely so this conversation does not repeat past decisions.
|
|
21
|
+
4. If a project rule in `.aioson/rules/` conflicts with a loaded decision, the project rule wins. Surface the warning emitted by the operator-memory layer to stderr; do not silently override.
|
|
22
|
+
|
|
23
|
+
If `AIOSON_OPERATOR_MEMORY=false` is set: skip silently. Backward compatible.
|
|
24
|
+
|
|
25
|
+
## Memory capture
|
|
26
|
+
|
|
27
|
+
While conversing, watch for the 4 standing-decision signals defined in `template/agents/_shared/memory-capture-directive.md` (authorization, exclusion, correction, confirmation 2x+). When you detect one, emit:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
aioson op:capture --signal=<type> --quote="<verbatim>" --proposal="<paraphrase>" --source-agent=<self>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Capture is best-effort — do not crash, retry, or surface failures to the user. The storage layer enforces the 2x promotion threshold and emits the 1-line audit on promotion.
|
|
34
|
+
|
|
12
35
|
## Agents
|
|
13
36
|
- /setup -> `.aioson/agents/setup.md`
|
|
14
37
|
- /discovery-design-doc -> `.aioson/agents/discovery-design-doc.md`
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: memory-capture-directive
|
|
3
|
+
schema_version: "1.0"
|
|
4
|
+
ships_with: operator-memory v1.13.0+
|
|
5
|
+
purpose: "Versioned prompt template defining the 4 signal types that agents observe and emit aioson op:capture for. Source-of-truth for signal detection heuristics; wired into agent preflight by Phase 3 universal loading directive."
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Memory Capture Directive (operator-memory v1.13.0)
|
|
9
|
+
|
|
10
|
+
> **Loaded by:** the universal loading directive in `template/CLAUDE.md` / `template/AGENTS.md` (Phase 3, v1.14.0). Phase 2 ships this file dormant — Phase 3 wires it in.
|
|
11
|
+
>
|
|
12
|
+
> **Versioned:** if signal taxonomy changes in V2, bump `schema_version` and update the loading directive's reference. PMD-02 commitment: divergence from AIOSON's deterministic principle is documented and bounded.
|
|
13
|
+
|
|
14
|
+
## What to watch for
|
|
15
|
+
|
|
16
|
+
While conversing with the user, watch their messages for **standing decisions** — preferences they want applied to *future* sessions, not just the current turn. There are exactly 4 signal types in V1.
|
|
17
|
+
|
|
18
|
+
### 1. Authorization
|
|
19
|
+
|
|
20
|
+
User grants ongoing permission for an action. Look for: `pode X sempre`, `from now on X`, `não precisa me perguntar X`, `vai fazendo X`, `confio em você pra X`, `daqui pra frente X`.
|
|
21
|
+
|
|
22
|
+
**Examples that ARE authorization:**
|
|
23
|
+
|
|
24
|
+
- "pode commitar autonomamente sempre que aprovar a fatia"
|
|
25
|
+
- "from now on, use TypeScript by default in new files"
|
|
26
|
+
- "não precisa me perguntar antes de rodar npm test, pode rodar direto"
|
|
27
|
+
|
|
28
|
+
**Examples that are NOT (do not capture):**
|
|
29
|
+
|
|
30
|
+
- "agora pode commitar" → context-bound to current task, not standing
|
|
31
|
+
- "ok faz isso" → simple agreement, not authorization
|
|
32
|
+
|
|
33
|
+
### 2. Exclusion
|
|
34
|
+
|
|
35
|
+
User explicitly carves out an action that they keep manual / restricted. Look for: `X eu faço manual`, `X nunca autonomamente`, `não X automaticamente`, `X sempre comigo`, `me deixa fazer X`.
|
|
36
|
+
|
|
37
|
+
**Examples that ARE exclusion:**
|
|
38
|
+
|
|
39
|
+
- "npm publish eu sempre faço manualmente"
|
|
40
|
+
- "git push para main nunca autonomamente"
|
|
41
|
+
- "deploy de produção é sempre comigo"
|
|
42
|
+
|
|
43
|
+
**Examples that are NOT:**
|
|
44
|
+
|
|
45
|
+
- "agora não publica" → context-bound
|
|
46
|
+
- "espera eu testar" → temporal, not standing
|
|
47
|
+
|
|
48
|
+
### 3. Correction
|
|
49
|
+
|
|
50
|
+
User explicitly tells you to stop doing something or change behavior going forward. Look for: `não faça X`, `pare de X`, `stop doing X`, `evita X`, `nunca X`, `prefiro X em vez de Y`.
|
|
51
|
+
|
|
52
|
+
**Examples that ARE correction:**
|
|
53
|
+
|
|
54
|
+
- "stop adding emojis to commit messages"
|
|
55
|
+
- "não faça mais resumos no fim de cada resposta"
|
|
56
|
+
- "prefiro respostas curtas em vez de longas"
|
|
57
|
+
|
|
58
|
+
**Examples that are NOT (likely one-shot):**
|
|
59
|
+
|
|
60
|
+
- "neste arquivo prefiro brevidade" → file-scoped
|
|
61
|
+
- "agora vai com cuidado" → session-scoped
|
|
62
|
+
|
|
63
|
+
### 4. Confirmation (2x+ threshold)
|
|
64
|
+
|
|
65
|
+
User accepts the same non-obvious approach twice without pushback. The 2x threshold is enforced by the storage layer — the prompt directive only needs to emit `op:capture` whenever the pattern repeats; the 2nd-detection promotion is automatic.
|
|
66
|
+
|
|
67
|
+
**Examples that ARE confirmation worth capturing:**
|
|
68
|
+
|
|
69
|
+
- User accepts the same unusual architectural choice across 2 PRs without questioning it
|
|
70
|
+
- User repeatedly says "perfect, keep doing X" for an approach that wasn't obvious
|
|
71
|
+
|
|
72
|
+
**Examples that are NOT:**
|
|
73
|
+
|
|
74
|
+
- Single acceptance ("ok") — wait for repetition
|
|
75
|
+
- Acceptance of trivially-correct approaches — no signal value
|
|
76
|
+
|
|
77
|
+
## How to emit
|
|
78
|
+
|
|
79
|
+
When you detect any of the 4 signals, emit this exact CLI call (best-effort — if it fails, do NOT crash the session):
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
aioson op:capture \
|
|
83
|
+
--signal=<authorization|exclusion|correction|confirmation> \
|
|
84
|
+
--quote="<verbatim user message>" \
|
|
85
|
+
--proposal="<your paraphrase of the standing decision>" \
|
|
86
|
+
--source-agent=<your-agent-name>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Field guidance:**
|
|
90
|
+
|
|
91
|
+
- `--quote` — the EXACT user words (verbatim) that triggered detection. Used for audit; trimmed automatically.
|
|
92
|
+
- `--proposal` — your one-sentence paraphrase in user-facing language. This becomes the slug seed + the decision body. Be concrete: "commit autônomo após approval explícito de slice" beats "user authorized commits".
|
|
93
|
+
- `--source-agent` — your own agent name (`dev`, `deyvin`, `pm`, etc.) so the audit trail knows which agent observed the signal.
|
|
94
|
+
|
|
95
|
+
## When NOT to capture (anti-patterns)
|
|
96
|
+
|
|
97
|
+
Suppress capture in these cases — they create noise that drowns real signal:
|
|
98
|
+
|
|
99
|
+
1. **Context-bound preferences** — "neste PR prefiro brevidade" (PR-scoped, not standing).
|
|
100
|
+
2. **Negotiations / questions** — "será que dá pra commitar autonomo?" (asking, not deciding).
|
|
101
|
+
3. **Routine agreements** — "ok", "sim", "vai" without specific scope (no signal).
|
|
102
|
+
4. **Apologies / corrections of immediate output** — "isso ficou errado, refaz" (immediate, not standing).
|
|
103
|
+
5. **Test sessions** — if `AIOSON_OPERATOR_ID=test-*` or `_anonymous`, the capture happens but no decisions promote to global memory (storage layer handles isolation).
|
|
104
|
+
6. **Conflict with project rules** — if a decision would conflict with `.aioson/rules/*.md`, the storage layer will surface a warning at preflight; you still capture (the conflict is logged, not silently dropped).
|
|
105
|
+
|
|
106
|
+
## Capture is best-effort
|
|
107
|
+
|
|
108
|
+
If `aioson op:capture` exits non-zero (CLI unavailable, storage failure, etc.), DO NOT crash the session, retry, or surface the failure to the user. The capture is informational — failure here is non-critical. Continue with the conversation normally.
|
|
109
|
+
|
|
110
|
+
The storage layer (Phase 2 v1.13.0 onwards) handles:
|
|
111
|
+
|
|
112
|
+
- Deterministic slug derivation (same paraphrase → same slug)
|
|
113
|
+
- Idempotent capture (re-detection updates `last_detected`, increments `detected_count`)
|
|
114
|
+
- 2x threshold promotion (proposal → decision atomic transition)
|
|
115
|
+
- Silent operation on first detection; 1-line audit on promotion
|