wicked-garden 12.55.0 → 12.56.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +2 -2
- package/CHANGELOG.md +39 -1
- package/CONTRIBUTING.md +1 -1
- package/README.md +3 -3
- package/docs/extending.md +1 -1
- package/docs/required-peers.md +2 -2
- package/package.json +2 -2
- package/pyproject.toml +5 -1
- package/schemas/wicked-pack.schema.json +1 -1
- package/scripts/_pack_registry.py +1 -1
- package/scripts/loom/manifest.py +5 -4
- package/scripts/qe/lib/gate.mjs +9 -7
- package/scripts/qe/lib/vault-evidence.mjs +16 -18
- package/scripts/qe/runner/README.md +5 -6
- package/scripts/qe/runner/test/th17-vault-evidence.test.mjs +6 -6
- package/skills/archetype/refs/incident.md +2 -2
- package/skills/archetype/refs/migrate.md +1 -1
- package/skills/archetype/refs/modernize.md +1 -1
- package/skills/archetype/refs/review.md +1 -1
- package/skills/archetype/refs/specify.md +1 -1
- package/skills/core/refs/setup.md +6 -6
- package/skills/mem/SKILL.md +11 -3
- package/skills/mem/refs/scopes.md +16 -4
- package/skills/mem-capture/SKILL.md +60 -7
- package/skills/qe/refs/campaign-grading.md +4 -4
- package/skills/qe/refs/evidence.md +4 -4
- package/skills/repo-learn/SKILL.md +14 -11
- package/skills/repo-learn/refs/capture-proposals.md +28 -20
- package/skills/search/refs/answer.md +4 -3
- package/uv.lock +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name": "wicked-garden", "owner": {"name": "Mike Parcewski"}, "plugins": [{"name": "wicked-garden", "source": "./", "description": "Your coding agent already plans and swarms \u2014 Wicked Garden is the curated toolkit for what it can't: proof-not-claims gates, code links grep can't see, deterministic refactor, cross-session memory, multi-model second opinions (fallback seats labelled). Don't fight the harness; fill its gaps. The gate needs wicked-vault (a self-contained infra peer, installed directly) and re-derives through garden's built-in engine; estate/bus are opt-in layers (wicked-testing and wicked-brain are retired \u2014 QE ships in-catalog as the qe domain, memory lives in wicked-estate).", "version": "12.
|
|
1
|
+
{"name": "wicked-garden", "owner": {"name": "Mike Parcewski"}, "plugins": [{"name": "wicked-garden", "source": "./", "description": "Your coding agent already plans and swarms \u2014 Wicked Garden is the curated toolkit for what it can't: proof-not-claims gates, code links grep can't see, deterministic refactor, cross-session memory, multi-model second opinions (fallback seats labelled). Don't fight the harness; fill its gaps. The gate needs wicked-vault (a self-contained infra peer, installed directly) and re-derives through garden's built-in engine; estate/bus are opt-in layers (wicked-testing and wicked-brain are retired \u2014 QE ships in-catalog as the qe domain, memory lives in wicked-estate).", "version": "12.56.0"}], "version": "12.56.0"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wicked-garden",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.56.0",
|
|
4
4
|
"description": "Your coding agent's harness already plans and swarms; Wicked Garden is the curated toolkit for what it can't do alone. Proof, not claims \u2014 gates re-derive 'done' through the internal loom engine (fail-closed, independently attested via wicked-vault), so a self-asserted pass can't lie its way green. Relationships grep can't see \u2014 the wicked-estate code graph + injected bus/dispatch/capability/archetype edges power blast-radius & lineage. Plus deterministic multi-file refactor (wicked-patch), cross-session memory + knowledge (the mem domain over wicked-estate), multi-model second opinions (fallback seats labelled) (jam:council), portable expertise as on-demand skill-refs, and evidence-gated testing (the in-catalog qe domain). It reads the shape of your work to apply the right rigor \u2014 steering, not a pipeline \u2014 then gets out of the way. The compiler stamps a self-contained evidence gate into any repo that runs with no wicked-garden installed. Don't fight the harness; fill its gaps. The evidence gate requires wicked-vault, a self-contained infra peer wicked-garden installs directly; wicked-bus is an opt-in layer \u2014 install what you'll use, the toolkit works without the rest.",
|
|
5
|
-
"wicked_vault_version": "
|
|
5
|
+
"wicked_vault_version": ">=0.8.0",
|
|
6
6
|
"wicked_ledger_version": "^0.6.0",
|
|
7
7
|
"wicked_bus_version": "^2.0.0",
|
|
8
8
|
"author": {
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,42 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [12.56.0] — 2026-10-17
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **Operator memories and an explicit reach (needs wicked-estate with the operator scope).**
|
|
9
|
+
- How the user works (style, preferences, the extra steps they always take) is an operator memory. `mem-capture` stores it at `operator:local`, which every project's recall includes, so it is never pinned to one project.
|
|
10
|
+
- Every policy proposal now carries `payload.reach`: `operator` (every project), or `project` (that project or repo). A rule the user states defaults to `operator` unless they named a project. A rule repo-learn learns from a repo is `project`.
|
|
11
|
+
- `mem/refs/scopes.md` documents the operator scope and the reach vocabulary.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- **Session capture files standing rules for review instead of storing them as memory.** The
|
|
15
|
+
`mem-capture` worker swept "always use…", "never do…" and team conventions into the memory
|
|
16
|
+
batch, so an enforceable rule became a memory nobody approved. A standing rule the user stated
|
|
17
|
+
now goes to the review queue as a `policy:<type>` proposal (Step 3b); a preference that is not a
|
|
18
|
+
checkable rule stays a memory. The `mem` skill and `refs/scopes.md` say the same.
|
|
19
|
+
- **repo-learn no longer files code-wiring facts as memory.** Its 2×2 map and "derive both"
|
|
20
|
+
guidance told the worker to record "how X wires up" as a memory, contradicting its own rule that
|
|
21
|
+
what is read from code is knowledge. Those findings are now `knowledge` proposals; a memory is
|
|
22
|
+
only what the worker witnessed or was told. The skill's summary and memory guidance say the
|
|
23
|
+
same, and a convention the team must follow is a policy. Its capture reference no longer
|
|
24
|
+
documents piping long JSON to `propose -` (the shim never read stdin).
|
|
25
|
+
- **Onboarding records the detected languages, frameworks and tools as knowledge.** `core` setup
|
|
26
|
+
stored them as a `skill` memory; they are read from the repository, so they go through the mem
|
|
27
|
+
`write` action now.
|
|
28
|
+
- **Answer synthesis takes "what should hold" from approved steering rules, not memory.** On a
|
|
29
|
+
conflict, `search` answer cited an operator memory as the ruling; an approved rule
|
|
30
|
+
(`rules.recall`) now governs, and a memory gives what was decided and why.
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
- **The site's skill count is counted at build time, and the council is described as what it is.** `site/astro.config.mjs` counts `SKILL.md` under `skills/**` (`__WICKED_GARDEN_SKILLS__`), so the hero, the toolbox and the page description can no longer disagree (they said 143 and 142; the tree holds 138). The site no longer says "the multi-model council IS the router": a panel of other models settles a disputed decision. The hero drops "capability plane" for plain words, the README drops the retired Zed/ACP mention, and the npm description names every host it installs into (takes effect on the next publish).
|
|
34
|
+
|
|
35
|
+
## [12.55.1] — 2026-10-15
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
- **Bump the `wicked-vault` peer floor to `>= 0.8.0` and drop stale "unreleased manifest-2.1 twin" notes (garden#1309).** `.claude-plugin/plugin.json` now declares `"wicked_vault_version": ">=0.8.0"` (replacing `"^0.5.0"`, whose `0.x` caret excluded every later minor), in lockstep with `scripts/loom/manifest.py` (`version_pin="0.8"`) and every `<!-- vault-floor -->` doc/skill restatement. `VAULT_RELEASE_REQUIREMENT` in `scripts/qe/lib/vault-evidence.mjs` and the QE docs/help strings now point to `npm i -g wicked-vault@latest` (the manifest-2.1 twin shipped in 0.7.0; 0.8.0 is the current floor).
|
|
39
|
+
- **The plugin's Python range stops below 3.15 until its dependencies ship 3.15 wheels.** `pydantic-core` (via `pydantic`) has no CPython 3.15 wheel. A 3.15 default interpreter (the macOS GitHub runners and Homebrew `python@3.15`) made `uv sync` build it from source with Rust, which fails without a toolchain. That blocked wicked-crew's first skills publish (its release smoke S02 on macOS, and any 3.15-only host without Rust). `requires-python` is now `>=3.10,<3.15` (uv.lock relocked at the same lock revision), so uv picks or downloads a 3.14. Lift the bound once pydantic-core publishes cp315 wheels.
|
|
40
|
+
|
|
5
41
|
## [12.55.0] — 2026-10-14
|
|
6
42
|
|
|
7
43
|
### Added
|
|
@@ -1129,7 +1165,9 @@ through `v9.2.18`. Major themes across that span:
|
|
|
1129
1165
|
|
|
1130
1166
|
For each of those releases, see the corresponding tag in git history.
|
|
1131
1167
|
|
|
1132
|
-
[Unreleased]: https://github.com/mikeparcewski/wicked-garden/compare/v12.
|
|
1168
|
+
[Unreleased]: https://github.com/mikeparcewski/wicked-garden/compare/v12.56.0...HEAD
|
|
1169
|
+
[12.56.0]: https://github.com/mikeparcewski/wicked-garden/compare/v12.55.1...v12.56.0
|
|
1170
|
+
[12.55.1]: https://github.com/mikeparcewski/wicked-garden/compare/v12.55.0...v12.55.1
|
|
1133
1171
|
[12.55.0]: https://github.com/mikeparcewski/wicked-garden/compare/v12.54.0...v12.55.0
|
|
1134
1172
|
[12.54.0]: https://github.com/mikeparcewski/wicked-garden/compare/v12.53.3...v12.54.0
|
|
1135
1173
|
[12.53.3]: https://github.com/mikeparcewski/wicked-garden/compare/v12.53.2...v12.53.3
|
package/CONTRIBUTING.md
CHANGED
|
@@ -29,7 +29,7 @@ uv run pytest tests/ -x
|
|
|
29
29
|
|
|
30
30
|
**For offline CI and dev environments without the wicked-vault peer only.**
|
|
31
31
|
|
|
32
|
-
wicked-vault (npm, ≥ 0.
|
|
32
|
+
wicked-vault (npm, ≥ 0.8.0 <!-- vault-floor -->, install `npm i -g wicked-vault`)
|
|
33
33
|
is the one required peer (the loom engine is built into the garden; bus is an
|
|
34
34
|
opt-in layer). The garden's produces-gates re-derive
|
|
35
35
|
evidence through the built-in loom engine — `scripts/qe/vault_gate.py` runs
|
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
## The premise
|
|
19
19
|
|
|
20
|
-
Coding agents grew up. Claude Code, Codex, Cursor, Antigravity, Aider, OpenCode
|
|
20
|
+
Coding agents grew up. Claude Code, Codex, Cursor, Antigravity, Aider, OpenCode — they're not autocomplete anymore. They plan. They parallelize. And each has *strong opinions* about how it likes to work.
|
|
21
21
|
|
|
22
22
|
Most plugins try to boss them around — re-implement planning, impose a workflow, make the agent dance. You end up fighting your own tools.
|
|
23
23
|
|
|
@@ -86,7 +86,7 @@ Then, in a Claude Code session:
|
|
|
86
86
|
**One required peer, the rest opt-in.** The evidence gate is the floor we won't fake, so it needs one external peer — setup blocks without it:
|
|
87
87
|
|
|
88
88
|
```bash
|
|
89
|
-
npm i -g wicked-vault # wicked-vault (≥ 0.
|
|
89
|
+
npm i -g wicked-vault # wicked-vault (≥ 0.8.0), the honest-evidence backend the gate re-derives against
|
|
90
90
|
```
|
|
91
91
|
|
|
92
92
|
> The gate/resolve engine (formerly the separate `wicked-loom` package) is now **absorbed in-package** as of v12.27.0 (`scripts/loom/`) — nothing extra to install. The gate re-hashes recorded evidence and re-runs its verifier through that engine; a false "tests pass" is **rejected**, a missing backend **fails closed**.
|
|
@@ -170,7 +170,7 @@ Full author guide: [`docs/extending.md`](docs/extending.md).
|
|
|
170
170
|
|
|
171
171
|
## Requirements
|
|
172
172
|
|
|
173
|
-
A coding-agent harness ([Claude Code](https://docs.anthropic.com/en/docs/claude-code/overview) ≥ 1.0 for the plugin surface; the peers + compiled gate are harness-agnostic) · Python 3.9+ (stdlib-only hooks) · Node + `npx` · the gate's one required peer (`wicked-vault` ≥ 0.
|
|
173
|
+
A coding-agent harness ([Claude Code](https://docs.anthropic.com/en/docs/claude-code/overview) ≥ 1.0 for the plugin surface; the peers + compiled gate are harness-agnostic) · Python 3.9+ (stdlib-only hooks) · Node + `npx` · the gate's one required peer (`wicked-vault` ≥ 0.8.0) plus opt-in layers (`wicked-estate` · `wicked-bus`).
|
|
174
174
|
|
|
175
175
|
## License
|
|
176
176
|
|
package/docs/extending.md
CHANGED
|
@@ -51,7 +51,7 @@ A complete working example (used as garden's own e2e fixture):
|
|
|
51
51
|
]
|
|
52
52
|
}
|
|
53
53
|
],
|
|
54
|
-
"peers": { "wicked-garden": ">=12.0.0", "wicked-vault": ">=0.
|
|
54
|
+
"peers": { "wicked-garden": ">=12.0.0", "wicked-vault": ">=0.8.0" },
|
|
55
55
|
"provenance": { "source": "https://github.com/acme/acme-seo-pack", "publisher": "acme" }
|
|
56
56
|
}
|
|
57
57
|
```
|
package/docs/required-peers.md
CHANGED
|
@@ -18,7 +18,7 @@ works.
|
|
|
18
18
|
|
|
19
19
|
| Peer | What it does | Install |
|
|
20
20
|
|------|--------------|---------|
|
|
21
|
-
| **wicked-vault** | The honest-evidence backend the gate re-derives against: record → re-hash + re-run the verifier → cross-check. Never trusts a cached status. | `npm i -g wicked-vault` — puts the `wicked-vault` binary on PATH (optionally run `wicked-vault-install` afterwards to copy the vault skills into your AI CLIs). Declared floor: **≥ 0.
|
|
21
|
+
| **wicked-vault** | The honest-evidence backend the gate re-derives against: record → re-hash + re-run the verifier → cross-check. Never trusts a cached status. | `npm i -g wicked-vault` — puts the `wicked-vault` binary on PATH (optionally run `wicked-vault-install` afterwards to copy the vault skills into your AI CLIs). Declared floor: **≥ 0.8.0** <!-- vault-floor --> (below 0.8.0, upgrade with `npm i -g wicked-vault@latest` — the peer registry's health probe, `loom doctor` / the peer-health command, reports a below-floor vault as `drift` and fails its check). Resolved at runtime via `WICKED_VAULT_BIN` → config → `PATH` → `node_modules` → `npx wicked-vault`. |
|
|
22
22
|
|
|
23
23
|
The core skill's `setup` action (`/wicked-garden-core setup`) **blocks** without
|
|
24
24
|
it — a toolkit whose headline is "done is re-derived, not asserted" cannot ship
|
|
@@ -35,7 +35,7 @@ single source of truth; every doc restatement of the number is tagged with a
|
|
|
35
35
|
`<!-- vault-floor -->` marker (README's bash-comment restatement can't carry an
|
|
36
36
|
HTML comment, so grep the number too). **To bump the floor:** change
|
|
37
37
|
`manifest.py` + `plugin.json`, then
|
|
38
|
-
`grep -rn "vault-floor\|0\.
|
|
38
|
+
`grep -rn "vault-floor\|0\.8\.0" README.md CONTRIBUTING.md docs/ skills/` and
|
|
39
39
|
update every tagged restatement in the same commit.
|
|
40
40
|
|
|
41
41
|
## The built-in gate engine (loom) — nothing to install
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wicked-garden",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.56.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "The skills your coding agent can't build alone: \"done\" re-checked from evidence, graph-aware search and multi-file refactor, 40 QE specialists, review panels from other models, and cross-session memory. Works in Claude Code, Codex, Antigravity, OpenCode and Pi, in CI, or in a wicked-crew job.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"ai",
|
|
8
8
|
"coding-agent",
|
package/pyproject.toml
CHANGED
|
@@ -7,7 +7,11 @@ name = "wicked-garden"
|
|
|
7
7
|
# not bump it — PEP 621 requires a value, so it is pinned to the placeholder 0.0.0 (mirrored in uv.lock).
|
|
8
8
|
version = "0.0.0"
|
|
9
9
|
description = "AI-Native SDLC delivered as a single Claude Code plugin"
|
|
10
|
-
|
|
10
|
+
# <3.15 (garden 12.55.1): pydantic-core (via pydantic) ships no CPython 3.15 wheel yet, so a 3.15
|
|
11
|
+
# default interpreter (macOS runners and Homebrew since 2026-10) made `uv sync` build it from source
|
|
12
|
+
# with Rust — which fails without a toolchain, blocking crew's first skills publish. With the bound,
|
|
13
|
+
# uv picks (or downloads) a 3.14. Lift it once pydantic-core publishes cp315 wheels.
|
|
14
|
+
requires-python = ">=3.10,<3.15"
|
|
11
15
|
dependencies = [
|
|
12
16
|
"rapidfuzz>=3.0",
|
|
13
17
|
"aiofiles>=23.0",
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
},
|
|
108
108
|
"peers": {
|
|
109
109
|
"type": "object",
|
|
110
|
-
"description": "Peer version floors (extension-contract gap 6), e.g. {\"wicked-garden\": \">=12.29.0\", \"wicked-vault\": \">=0.
|
|
110
|
+
"description": "Peer version floors (extension-contract gap 6), e.g. {\"wicked-garden\": \">=12.29.0\", \"wicked-vault\": \">=0.8.0\"}. Checked FAIL-OPEN: violations are surfaced at SessionStart and by `pack floors`, never blocked on.",
|
|
111
111
|
"additionalProperties": { "type": "string", "pattern": "^(>=|\\^)\\s*\\d+\\.\\d+\\.\\d+$" }
|
|
112
112
|
},
|
|
113
113
|
"provenance": {
|
|
@@ -28,7 +28,7 @@ skills tree. There is NO signing — the hashes detect post-registration drift,
|
|
|
28
28
|
they do not prove authorship. See docs/extending.md "Trust model".
|
|
29
29
|
|
|
30
30
|
Peer floors (gap 6, fail-open): a pack may declare ``peers`` —
|
|
31
|
-
``{"wicked-garden": ">=12.29.0", "wicked-vault": ">=0.
|
|
31
|
+
``{"wicked-garden": ">=12.29.0", "wicked-vault": ">=0.8.0"}``.
|
|
32
32
|
``check_peer_floors()`` compares floors against what is actually installed
|
|
33
33
|
and returns violations as data. It NEVER raises and never blocks: an
|
|
34
34
|
unprobeable peer reports status "unknown", not a violation.
|
package/scripts/loom/manifest.py
CHANGED
|
@@ -94,10 +94,11 @@ PEERS: dict = {
|
|
|
94
94
|
name="vault",
|
|
95
95
|
npm_package="wicked-vault",
|
|
96
96
|
env_var="WICKED_VAULT_BIN",
|
|
97
|
-
# 0.
|
|
98
|
-
#
|
|
99
|
-
# MAJOR.MINOR floor in lockstep with
|
|
100
|
-
|
|
97
|
+
# 0.8 floor: the manifest-2.1 twin the QE evidence flow needs shipped
|
|
98
|
+
# in 0.7.0, and 0.8.0 enforces contract pins and re-validates
|
|
99
|
+
# attestations. Keep this MAJOR.MINOR floor in lockstep with
|
|
100
|
+
# plugin.json's ``wicked_vault_version``.
|
|
101
|
+
version_pin="0.8",
|
|
101
102
|
# wicked-vault is a DIRECT infra peer, published from its own repo
|
|
102
103
|
# (mikeparcewski/wicked-vault): self-contained, zero runtime deps. Install
|
|
103
104
|
# it directly. ``npm i -g wicked-vault``
|
package/scripts/qe/lib/gate.mjs
CHANGED
|
@@ -73,10 +73,10 @@
|
|
|
73
73
|
* - A bundle that failed manifest validation (downgraded above) is NOT
|
|
74
74
|
* vaulted — the downgraded INCONCLUSIVE verdict records with
|
|
75
75
|
* `vault: {skipped}` instead (never freeze a nonconforming bundle).
|
|
76
|
-
* - Release dependency: needs
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
76
|
+
* - Release dependency: needs wicked-vault >= 0.8.0 (the manifest-2.1 twin
|
|
77
|
+
* shipped in 0.7.0; garden's floor is 0.8.0). An older vault is refused
|
|
78
|
+
* fail-closed — upgrade with `npm i -g wicked-vault@latest` (or set
|
|
79
|
+
* `WICKED_QE_VAULT_PKG` to point at a specific 0.8.0+ install).
|
|
80
80
|
*/
|
|
81
81
|
|
|
82
82
|
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
@@ -339,7 +339,8 @@ export async function runGate({ projectId, runId, verdict, verdictSummary, ratio
|
|
|
339
339
|
// 2c. TH-17: resolve wicked-vault up front when vault integrity was asked
|
|
340
340
|
// for — fail fast (exit 3) on an unresolvable or pre-2.1 vault, BEFORE
|
|
341
341
|
// anything is written anywhere. The refusal message carries the release
|
|
342
|
-
// dependency (the manifest-2.1 twin
|
|
342
|
+
// dependency (the manifest-2.1 twin shipped in 0.7.0; floor is 0.8.0 —
|
|
343
|
+
// upgrade with `npm i -g wicked-vault@latest`).
|
|
343
344
|
const wantsVault = Boolean(vaultRecord || vaultEntry);
|
|
344
345
|
let vaultModule = null;
|
|
345
346
|
if (wantsVault) {
|
|
@@ -556,8 +557,9 @@ Optional:
|
|
|
556
557
|
(content-addressed) and attest the verdict as the reviewer's
|
|
557
558
|
opinion; the verdicts row carries vault_payload_sha. REFUSES
|
|
558
559
|
unredacted bundles (TH-19 ordering) — exit 3, nothing recorded.
|
|
559
|
-
Needs
|
|
560
|
-
|
|
560
|
+
Needs wicked-vault >= 0.8.0 (the manifest-2.1 twin shipped in
|
|
561
|
+
0.7.0; upgrade with \`npm i -g wicked-vault@latest\`, or set
|
|
562
|
+
WICKED_QE_VAULT_PKG to a specific 0.8.0+ install)
|
|
561
563
|
--vault-entry <id> TH-17: link an already-vaulted bundle instead of recording;
|
|
562
564
|
re-derived fail-closed before the verdict is recorded
|
|
563
565
|
--vault-actor <id> Recording (worker) identity for --vault-record (default: qe-runner)
|
|
@@ -44,12 +44,10 @@
|
|
|
44
44
|
*
|
|
45
45
|
* RELEASE DEPENDENCY (documented, enforced by `resolveVaultModule`):
|
|
46
46
|
* this flow needs the wicked-vault manifest-2.1 twin (`validateManifest` +
|
|
47
|
-
* `CLAIM_LEVELS` exports
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* `npm link` it); a pre-2.1 vault is refused fail-closed, never silently
|
|
52
|
-
* degraded.
|
|
47
|
+
* `CLAIM_LEVELS` exports, shipped in wicked-vault 0.7.0; garden's floor is
|
|
48
|
+
* 0.8.0). An older vault is refused fail-closed, never silently degraded —
|
|
49
|
+
* upgrade with `npm i -g wicked-vault@latest` (or set `WICKED_QE_VAULT_PKG`
|
|
50
|
+
* to point at a specific wicked-vault 0.8.0+ install).
|
|
53
51
|
*
|
|
54
52
|
* CLI (from the target repo's root):
|
|
55
53
|
* node vault-evidence.mjs record --evidence-dir <dir> [--repo-root <dir>]
|
|
@@ -75,10 +73,9 @@ import { scanForSecrets, compileExtraPatterns } from "../runner/src/redact.mjs";
|
|
|
75
73
|
|
|
76
74
|
/** The one-line release dependency, stamped on every pre-2.1 refusal. */
|
|
77
75
|
export const VAULT_RELEASE_REQUIREMENT =
|
|
78
|
-
"wicked-vault
|
|
79
|
-
"
|
|
80
|
-
"
|
|
81
|
-
"wicked-vault main, or `npm link wicked-vault` from one.";
|
|
76
|
+
"wicked-vault >= 0.8.0 is required (the manifest-2.1 twin, validateManifest + CLAIM_LEVELS, " +
|
|
77
|
+
"shipped in 0.7.0) — upgrade with `npm i -g wicked-vault@latest`, or set WICKED_QE_VAULT_PKG " +
|
|
78
|
+
"to a wicked-vault 0.8.0+ install.";
|
|
82
79
|
|
|
83
80
|
/** Typed refusal so callers (gate.mjs, tests) can tell WHY the write was refused. */
|
|
84
81
|
export class VaultEvidenceError extends Error {
|
|
@@ -116,9 +113,9 @@ function esmEntryForPackage(resolvedFile) {
|
|
|
116
113
|
|
|
117
114
|
/**
|
|
118
115
|
* Capability gate: is this module a wicked-vault WITH the manifest-2.1 twin?
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
* VAULT_RELEASE_REQUIREMENT). Exported for tests.
|
|
116
|
+
* The twin (`validateManifest` + `CLAIM_LEVELS`) shipped in wicked-vault 0.7.0
|
|
117
|
+
* and garden's floor is 0.8.0; an older vault without those exports is refused
|
|
118
|
+
* fail-closed (see VAULT_RELEASE_REQUIREMENT). Exported for tests.
|
|
122
119
|
*/
|
|
123
120
|
export function checkVaultCapability(mod) {
|
|
124
121
|
if (!mod || typeof mod !== "object") return { ok: false, reason: "not a module" };
|
|
@@ -135,8 +132,8 @@ export function checkVaultCapability(mod) {
|
|
|
135
132
|
|
|
136
133
|
/**
|
|
137
134
|
* Resolve the wicked-vault module, fail-closed on capability:
|
|
138
|
-
* 1. `WICKED_QE_VAULT_PKG` env —
|
|
139
|
-
*
|
|
135
|
+
* 1. `WICKED_QE_VAULT_PKG` env — optional pointer to a specific wicked-vault
|
|
136
|
+
* package dir (or its entry file).
|
|
140
137
|
* 2. bare `import("wicked-vault")` (global / hoisted install).
|
|
141
138
|
* 3. the target repo's node_modules (cwd-anchored resolution).
|
|
142
139
|
* A resolved-but-pre-2.1 vault is a refusal, not a fallback.
|
|
@@ -551,9 +548,10 @@ Subcommands:
|
|
|
551
548
|
Re-derive the bundle months later: vault hashes + every artifact
|
|
552
549
|
re-hashed on disk. Exit 1 on ANY divergence.
|
|
553
550
|
|
|
554
|
-
wicked-vault resolution: WICKED_QE_VAULT_PKG (
|
|
555
|
-
|
|
556
|
-
|
|
551
|
+
wicked-vault resolution: WICKED_QE_VAULT_PKG (optional pointer to a specific
|
|
552
|
+
wicked-vault 0.8.0+ install) → global install → the repo's node_modules. An
|
|
553
|
+
older vault without the manifest-2.1 twin (shipped in 0.7.0; floor 0.8.0) is
|
|
554
|
+
refused fail-closed — upgrade with \`npm i -g wicked-vault@latest\`.
|
|
557
555
|
|
|
558
556
|
Exit codes: 0 ok · 1 rederive divergence · 3 refusal / usage / system error.
|
|
559
557
|
`;
|
|
@@ -218,12 +218,11 @@ the reviewer's grade appended as an opinion attestation — see
|
|
|
218
218
|
--vault-record`. The vault payload is `manifest.json` (content-addressed; it
|
|
219
219
|
binds every artifact's sha256), so a campaign PASS re-derives months later.
|
|
220
220
|
**Release dependency:** the flow needs the wicked-vault manifest-2.1 twin
|
|
221
|
-
(`validateManifest` + `CLAIM_LEVELS`)
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
when no 2.1 vault is resolvable.
|
|
221
|
+
(`validateManifest` + `CLAIM_LEVELS`), which shipped in wicked-vault 0.7.0;
|
|
222
|
+
garden's floor is 0.8.0. An older vault is refused fail-closed — upgrade with
|
|
223
|
+
`npm i -g wicked-vault@latest` (or set `WICKED_QE_VAULT_PKG` to point at a
|
|
224
|
+
specific wicked-vault 0.8.0+ install). The `th17-vault-evidence` tests skip
|
|
225
|
+
with that message when no 2.1-capable vault is resolvable.
|
|
227
226
|
|
|
228
227
|
## Tests
|
|
229
228
|
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
* refusal happens in code, not in docs.
|
|
16
16
|
*
|
|
17
17
|
* Release dependency (documented in vault-evidence.mjs): these tests need
|
|
18
|
-
* the wicked-vault manifest-2.1 twin
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* one the vault-dependent tests SKIP
|
|
22
|
-
* mapping/capability tests still run).
|
|
18
|
+
* the wicked-vault manifest-2.1 twin (shipped in wicked-vault 0.7.0;
|
|
19
|
+
* garden's floor is 0.8.0). An older vault is refused fail-closed — upgrade
|
|
20
|
+
* with `npm i -g wicked-vault@latest` (or set WICKED_QE_VAULT_PKG to point
|
|
21
|
+
* at a specific 0.8.0+ install); without one the vault-dependent tests SKIP
|
|
22
|
+
* with that message (the pure mapping/capability tests still run).
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
25
|
import test from "node:test";
|
|
@@ -149,7 +149,7 @@ test("checkVaultCapability: a pre-2.1 vault is refused WITH the release requirem
|
|
|
149
149
|
const r = checkVaultCapability(pre21);
|
|
150
150
|
assert.equal(r.ok, false);
|
|
151
151
|
assert.equal(r.pre21, true);
|
|
152
|
-
assert.match(r.reason, /
|
|
152
|
+
assert.match(r.reason, /0\.8\.0/);
|
|
153
153
|
assert.match(r.reason, /WICKED_QE_VAULT_PKG/);
|
|
154
154
|
// and a non-vault module is a different refusal (not "release the vault")
|
|
155
155
|
const notVault = checkVaultCapability({ record: fn });
|
|
@@ -76,7 +76,7 @@ confirming the bleeding stopped. Don't skip to followup before resolve.
|
|
|
76
76
|
2. **Confirm the bleeding stopped.** Watch the same dashboards that
|
|
77
77
|
surfaced the incident. Don't declare mitigated based on logs alone.
|
|
78
78
|
3. Record the mitigation as re-derivable evidence (vault present;
|
|
79
|
-
**wicked-vault ≥ 0.
|
|
79
|
+
**wicked-vault ≥ 0.8.0** <!-- vault-floor -->):
|
|
80
80
|
`wicked-vault record --scope <scope> --phase incident --claim mitigation
|
|
81
81
|
--kind mitigation-check --source "<the symptom-check command>"
|
|
82
82
|
--criteria "symptom check passes post-mitigation"
|
|
@@ -106,7 +106,7 @@ confirming the bleeding stopped. Don't skip to followup before resolve.
|
|
|
106
106
|
2. Use `wicked-garden-qe-incident-to-scenario-synthesizer` to convert the
|
|
107
107
|
incident into a regression scenario that would catch the same break.
|
|
108
108
|
3. Track action items in github. Don't bury them in a Slack thread.
|
|
109
|
-
4. Record the docs evidence (vault present; **wicked-vault ≥ 0.
|
|
109
|
+
4. Record the docs evidence (vault present; **wicked-vault ≥ 0.8.0** <!-- vault-floor -->):
|
|
110
110
|
`wicked-vault record --scope <scope> --phase incident --claim rca
|
|
111
111
|
--kind doc --artifact docs/postmortems/INC-{N}.md
|
|
112
112
|
--criteria "required RCA sections present"
|
|
@@ -83,7 +83,7 @@ them mid-cutover. Absent? Discover it the usual way — and consider
|
|
|
83
83
|
the old shape.
|
|
84
84
|
3. Land + deploy expand. Don't combine with backfill.
|
|
85
85
|
4. Record the **shape-change** as re-derivable evidence (vault present;
|
|
86
|
-
**wicked-vault ≥ 0.
|
|
86
|
+
**wicked-vault ≥ 0.8.0** <!-- vault-floor -->):
|
|
87
87
|
`wicked-vault record --scope <scope> --phase migrate --claim shape-change
|
|
88
88
|
--kind schema-state --source "<migration-applied verification>"
|
|
89
89
|
--criteria "<the post-condition>" --verifier exit_code_eq:0
|
|
@@ -141,7 +141,7 @@ core's fail-closed build. See `skills/domain/SKILL.md`.
|
|
|
141
141
|
2. Harden the result with `code-modernization:modernize-harden` (security/CVEs,
|
|
142
142
|
error handling) before it carries traffic.
|
|
143
143
|
3. Record the parity proof as re-derivable evidence (vault present; **wicked-vault
|
|
144
|
-
≥ 0.
|
|
144
|
+
≥ 0.8.0** <!-- vault-floor -->):
|
|
145
145
|
`wicked-vault record --scope <scope> --phase modernize --claim parity-proof
|
|
146
146
|
--kind differential --source "<the differential harness command>"
|
|
147
147
|
--criteria "old(input) == new(input) on seeded data" --verifier exit_code_eq:0
|
|
@@ -121,7 +121,7 @@ in three domains").
|
|
|
121
121
|
4. Append to the audit log with `wicked-garden run scripts/qe/verdict_audit.py append`
|
|
122
122
|
so the verdict is replayable.
|
|
123
123
|
Then record both produces as re-derivable evidence (vault present;
|
|
124
|
-
**wicked-vault ≥ 0.
|
|
124
|
+
**wicked-vault ≥ 0.8.0** <!-- vault-floor -->):
|
|
125
125
|
`wicked-vault record --scope <scope> --phase review --claim verdict
|
|
126
126
|
--kind verdict --source "<verdict.json>" --criteria "<the bar>"
|
|
127
127
|
--verifier exit_code_eq:0 --actor "${WICKED_VAULT_ACTOR:-garden-prove}"
|
|
@@ -62,7 +62,7 @@ proceed past validate without explicit user agreement on the AC set.
|
|
|
62
62
|
4. Keep ACs minimal — 3–7 is the sweet spot. More than 10 means you're
|
|
63
63
|
treating ACs as design.
|
|
64
64
|
5. Record the AC artifact as re-derivable evidence (vault present;
|
|
65
|
-
**wicked-vault ≥ 0.
|
|
65
|
+
**wicked-vault ≥ 0.8.0** <!-- vault-floor -->):
|
|
66
66
|
`wicked-vault record --scope <scope> --phase specify
|
|
67
67
|
--claim smart-acceptance-criteria --kind spec-doc
|
|
68
68
|
--artifact <path/to/requirements.md>
|
|
@@ -97,7 +97,7 @@ npx wicked-vault --version 2>/dev/null || echo "MISSING"
|
|
|
97
97
|
```
|
|
98
98
|
|
|
99
99
|
- `MISSING` → blocking. wicked-vault is the evidence backend every archetype gate re-derives against — without it, "done" can only be self-asserted. Show "wicked-vault is not installed. wicked-garden requires it as a direct infra peer (sibling to wicked-bus)." **INTERACTIVE mode**: native prompt header "wicked-vault Required", options "Install now (Required)" = "Run: npm i -g wicked-vault" / "Exit setup" = "Cancel — I'll install manually and re-run". **PLAIN_TEXT mode**: present numbered options and STOP. If install: run `npm i -g wicked-vault` (puts the `wicked-vault` binary on PATH) and confirm the CLI resolves with `npx wicked-vault --version`. On failure, show stderr and exit with manual instructions (`npm i -g wicked-vault`). If exit: "Run `npm i -g wicked-vault` then restart by invoking the wicked-garden-core skill's `setup` action."
|
|
100
|
-
- Version string → compare it against the declared peer floor **≥ 0.
|
|
100
|
+
- Version string → compare it against the declared peer floor **≥ 0.8.0** <!-- vault-floor --> (single source: `scripts/loom/manifest.py` `version_pin`, lockstep with plugin.json `wicked_vault_version`). **Below the floor** (e.g. `0.7.0`) → tell the user to upgrade: "wicked-vault {version} is below the floor 0.8.0 — peer health checks (`loom doctor` / peer-health) report it as drift and fail. Upgrade: `npm i -g wicked-vault@latest`." At or above (e.g. `0.8.0`) → show "wicked-vault {version} — ready." Then verify the garden can resolve it for gating: `wicked-garden run scripts/qe/vault_gate.py resolve` should report `resolvable: true`. If `installed: false` (resolving only via npx), suggest `npm i -g wicked-vault` for faster gate latency — recommended, not a hard block.
|
|
101
101
|
|
|
102
102
|
### 2.7 Verify wicked-bus (Recommended — audit-trail layer)
|
|
103
103
|
|
|
@@ -233,16 +233,16 @@ First, ask which directories to onboard. **INTERACTIVE mode**: native prompt wit
|
|
|
233
233
|
|
|
234
234
|
**Hand-off** — open the `wicked-garden-mem` skill and run its `ingest` action with `{selected_directory}` as the argument; on Claude Code this is the Skill tool, on any other seat open the named skill from your catalog and carry it out inline, then continue here.
|
|
235
235
|
|
|
236
|
-
**Step D —
|
|
237
|
-
**Hand-off** — open the `wicked-garden-mem` skill and run its `
|
|
236
|
+
**Step D — Record the onboarding scan as knowledge**. `{DETECTED_TOOLS_SUMMARY}` lists only available tools (e.g. "gh, docker"). Languages, frameworks and tools were read from the repository, so they are knowledge, not memory:
|
|
237
|
+
**Hand-off** — open the `wicked-garden-mem` skill and run its `write` action with content `{project} project context: languages {DETECTED_LANGS}; frameworks {DETECTED_FWS}; tools available {DETECTED_TOOLS_SUMMARY}.`, `class=concept` and `source={selected_directory}`; on Claude Code this is the Skill tool, on any other seat open the named skill from your catalog and carry it out inline, then continue here.
|
|
238
238
|
|
|
239
239
|
Show: "Onboarding complete — knowledge store has {N} chunks (mem review reports totals)."
|
|
240
240
|
|
|
241
241
|
#### 5.2 Quick Scout
|
|
242
242
|
|
|
243
|
-
Ask which directories to scout (same question mode pattern as 5.1 — native prompt or plain text depending on mode). Then Glob/Read the key entry points and
|
|
243
|
+
Ask which directories to scout (same question mode pattern as 5.1 — native prompt or plain text depending on mode). Then Glob/Read the key entry points and record the detected context from Step 5.0 as knowledge (it was read from the repository):
|
|
244
244
|
|
|
245
|
-
**Hand-off** — open the `wicked-garden-mem` skill and run its `
|
|
245
|
+
**Hand-off** — open the `wicked-garden-mem` skill and run its `write` action with content `{project} project context (quick scout): languages {DETECTED_LANGS}; frameworks {DETECTED_FWS}; tools {DETECTED_TOOLS_SUMMARY}.`, `class=concept` and `source={project}`; on Claude Code this is the Skill tool, on any other seat open the named skill from your catalog and carry it out inline, then continue here.
|
|
246
246
|
|
|
247
247
|
#### 5.3 Skip
|
|
248
248
|
|
|
@@ -304,7 +304,7 @@ wicked-garden is ready!
|
|
|
304
304
|
Storage: Local (DomainStore)
|
|
305
305
|
wicked-estate: {"ready (binary present)" or "MISSING — memory/context layer degraded"}
|
|
306
306
|
wicked-bus: {"ready (skills installed)" or "MISSING — install required"}
|
|
307
|
-
wicked-vault: {version e.g. "0.
|
|
307
|
+
wicked-vault: {version e.g. "0.8.0 — ready" or "MISSING — install required" or "{version} — below the 0.8.0 floor, upgrade required"}
|
|
308
308
|
loom engine: {"ready (internal — scripts/loom/)" or "MISSING — garden installation problem"}
|
|
309
309
|
Onboarding: {Full | Quick scout | Skipped}
|
|
310
310
|
Directories: {paths onboarded}
|
package/skills/mem/SKILL.md
CHANGED
|
@@ -97,7 +97,9 @@ A chat seat asked by wicked-crew to label the operator's decisions reads
|
|
|
97
97
|
(`{"content","class":"concept","source"}`) or `ingest` instead; `store`
|
|
98
98
|
refuses content that carries a `source`.
|
|
99
99
|
2. Pick `kind` (+ tier defaults): `fact` → semantic (decisions, gotchas,
|
|
100
|
-
stable facts) · `skill` → procedural (patterns,
|
|
100
|
+
stable facts) · `skill` → procedural (patterns, how-tos; a convention the
|
|
101
|
+
team must follow is a rule: propose it as `policy:<type>`, see the
|
|
102
|
+
mem-capture worker's Step 3b) ·
|
|
101
103
|
`entity` → semantic (a person/system profile). Add `about` tags for
|
|
102
104
|
recall hooks.
|
|
103
105
|
3. Run the backend:
|
|
@@ -117,7 +119,8 @@ A chat seat asked by wicked-crew to label the operator's decisions reads
|
|
|
117
119
|
|
|
118
120
|
By default recall searches the current project (`project:<cwd-basename>`)
|
|
119
121
|
and its ancestors, so root-scoped memories stay visible and other projects'
|
|
120
|
-
memories do not leak in.
|
|
122
|
+
memories do not leak in. Operator memories (`operator:<id>`, how the user
|
|
123
|
+
works) are recalled in every project. Pass `"scope"` to recall another project the same
|
|
121
124
|
way. Searching everything, brain-migrated leaves
|
|
122
125
|
(`brain:<project>/doc:<id>`) included, is an explicit opt-in:
|
|
123
126
|
`"scope_prefix": ""` (or `"scope_prefix": "project:<name>"` for one subtree). Items return content, scope, tier,
|
|
@@ -175,7 +178,12 @@ Dispatch the **wicked-garden-mem-capture** fork worker at session end ("
|
|
|
175
178
|
capture what we learned", before /clear or exit). It sweeps the conversation
|
|
176
179
|
for decisions, patterns, gotchas, discoveries, and preferences, classifies
|
|
177
180
|
each onto the estate kind/tier vocabulary, and batch-writes them via
|
|
178
|
-
`capture-batch`.
|
|
181
|
+
`capture-batch`. A standing rule the user stated ("always…", "never…") is
|
|
182
|
+
filed as a `policy:<type>` proposal for review (reach `operator`, every
|
|
183
|
+
project, unless they named a project), not stored as a memory. How the user
|
|
184
|
+
works (style, preferences, standing extra steps) is an operator memory at
|
|
185
|
+
`operator:local`, recalled in every project.
|
|
186
|
+
Report what it stored and proposed.
|
|
179
187
|
|
|
180
188
|
No hook extracts memories from the transcript. The Stop hook used to
|
|
181
189
|
pattern-match "decided to…" / "going to…" and filled the store with
|
|
@@ -14,8 +14,18 @@ project:wicked-garden
|
|
|
14
14
|
org:acme/agent:claude
|
|
15
15
|
brain:wicked-garden/doc:4f2a91
|
|
16
16
|
project:wicked-estate/session:2026-08-11
|
|
17
|
+
operator:local
|
|
17
18
|
```
|
|
18
19
|
|
|
20
|
+
**Operator scope.** `operator:<id>` (`operator:local` by default) holds
|
|
21
|
+
memories about how the operator works: style, preferences, the extra steps
|
|
22
|
+
they always take. Every scoped recall includes it, whatever the project, so
|
|
23
|
+
these follow the operator everywhere. A memory about a project's work stays
|
|
24
|
+
at `project:<name>`. A rule the operator wants enforced is neither: it is a
|
|
25
|
+
`policy:<type>` proposal. A proposal says which with `payload.reach`:
|
|
26
|
+
`project`, `pattern`, or `operator`. For a policy it is `project` or
|
|
27
|
+
`operator`.
|
|
28
|
+
|
|
19
29
|
Rules of thumb:
|
|
20
30
|
|
|
21
31
|
- **Store** under the narrowest scope that still makes the memory findable.
|
|
@@ -24,8 +34,9 @@ Rules of thumb:
|
|
|
24
34
|
- **Recall** uses one of two filters (mutually exclusive on the wire):
|
|
25
35
|
- `scope` — estate's ancestor-visible inheritance: memories at this scope
|
|
26
36
|
plus those inherited from ancestor scopes. **The default**, at
|
|
27
|
-
`project:<cwd-basename>`, so a session sees its own project's memories
|
|
28
|
-
|
|
37
|
+
`project:<cwd-basename>`, so a session sees its own project's memories,
|
|
38
|
+
root-scoped ones and operator memories (`operator:<id>`), never another
|
|
39
|
+
project's.
|
|
29
40
|
- `scope_prefix` — subtree match: every memory whose scope equals the
|
|
30
41
|
prefix or descends from it. `scope_prefix: ""` = the root subtree =
|
|
31
42
|
**everything**. Opt-in only: pass it when the user asks to search
|
|
@@ -47,7 +58,7 @@ for review or cleanup).
|
|
|
47
58
|
| Kind | Default tier | Store when… |
|
|
48
59
|
|------|--------------|-------------|
|
|
49
60
|
| `fact` | `semantic` | a decision, gotcha, or stable distilled fact ("we chose X because Y") |
|
|
50
|
-
| `skill` | `procedural` | a pattern
|
|
61
|
+
| `skill` | `procedural` | a pattern or how-to that gets reinforced by use (a convention the team must follow is a rule: a `policy:<type>` proposal, not a memory) |
|
|
51
62
|
| `episode` | `episodic` | raw experience estate distills from; not a capture target (store the rule an event taught as a `fact`) |
|
|
52
63
|
| `entity` | `semantic` | a profile of a person/system/component |
|
|
53
64
|
| `working` | `working` | session-local scratch written by hooks; estate expires it after 24 h |
|
|
@@ -68,7 +79,8 @@ Brain's memory types map onto estate kinds as follows (used by
|
|
|
68
79
|
|------------|-------------|------|
|
|
69
80
|
| decision | `fact` | `semantic` |
|
|
70
81
|
| pattern / procedural | `skill` | `procedural` |
|
|
71
|
-
| preference | `fact` | `semantic` |
|
|
82
|
+
| preference, style, standing extra step (how the operator works) | `fact` at `operator:local` | `semantic` |
|
|
83
|
+
| standing rule ("always…", "never…") | none: a `policy:<type>` proposal | n/a |
|
|
72
84
|
| gotcha | `fact` | `semantic` |
|
|
73
85
|
| discovery | `fact` (the rule it taught) | `semantic` |
|
|
74
86
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: wicked-garden-mem-capture
|
|
3
|
-
description: "Session-teardown memory capture: sweep the conversation for durable learnings (decisions with a reason, patterns, gotchas, preferences), keep only what passes the durability test, classify each onto the estate kind/tier vocabulary, and batch-write them to wicked-estate memory. Use when: dispatched by the wicked-garden-mem skill's capture action, at session end, before /clear or exit, or when the user says 'capture what we learned' / 'remember this session'."
|
|
3
|
+
description: "Session-teardown memory capture: sweep the conversation for durable learnings (decisions with a reason, patterns, gotchas, preferences), keep only what passes the durability test, classify each onto the estate kind/tier vocabulary, and batch-write them to wicked-estate memory; standing rules the user stated go to the review queue as policy proposals instead. Use when: dispatched by the wicked-garden-mem skill's capture action, at session end, before /clear or exit, or when the user says 'capture what we learned' / 'remember this session'."
|
|
4
4
|
metadata:
|
|
5
5
|
role: worker
|
|
6
6
|
---
|
|
@@ -26,9 +26,17 @@ Relative paths in this skill are relative to the directory that contains this SK
|
|
|
26
26
|
Look for things the session *learned*, not things it *did*:
|
|
27
27
|
|
|
28
28
|
- **Decisions with a reason**: "chose X over Y because…"
|
|
29
|
-
- **Patterns
|
|
29
|
+
- **Patterns**: "this always…" (how something behaves, witnessed)
|
|
30
30
|
- **Gotchas**: "this broke because…", "don't X because…"
|
|
31
|
-
- **
|
|
31
|
+
- **Standing rules** the user wants ENFORCED on the work: "always use…",
|
|
32
|
+
"never do…", "the convention is…", something a change can be checked
|
|
33
|
+
against ("UI work is not done without a screenshot"). These are steering, not memory: Step 3b files them as policy
|
|
34
|
+
proposals for review.
|
|
35
|
+
- **How the user works**: their style, preferences and the extra steps they
|
|
36
|
+
always take ("prefers tables in replies", "likes short commit subjects",
|
|
37
|
+
"usually opens the rendered page before reviewing CSS"). When the user
|
|
38
|
+
said it must be enforced, it is a standing rule instead. These are
|
|
39
|
+
**operator memories**: they apply in every project (Step 3).
|
|
32
40
|
|
|
33
41
|
Then apply the **provenance test**: memory is what we *witnessed*, were
|
|
34
42
|
*told*, or *decided*. What was read out of code, docs or the web is
|
|
@@ -74,14 +82,57 @@ applies), then map it onto the estate vocabulary
|
|
|
74
82
|
| Finding | `kind` | tier (default) |
|
|
75
83
|
|---------|--------|----------------|
|
|
76
84
|
| decision, preference, gotcha, stable fact | `fact` | `semantic` |
|
|
77
|
-
| pattern,
|
|
85
|
+
| pattern, how-to | `skill` | `procedural` |
|
|
86
|
+
|
|
87
|
+
A standing rule is not in this table: it goes to Step 3b, never to the
|
|
88
|
+
memory batch.
|
|
78
89
|
|
|
79
90
|
Events ("X happened when Y") are not memories. Keep only the rule the event
|
|
80
91
|
taught, as a `fact`.
|
|
81
92
|
|
|
82
93
|
Add 2–5 `about` tags per memory (systems, components, topics mentioned) so
|
|
83
|
-
recall has hooks.
|
|
84
|
-
|
|
94
|
+
recall has hooks.
|
|
95
|
+
|
|
96
|
+
Scope follows what the memory is about:
|
|
97
|
+
|
|
98
|
+
- **About this project or its code** (a decision, gotcha or pattern here):
|
|
99
|
+
leave the default (`project:<cwd-basename>`).
|
|
100
|
+
- **About how the user works** (style, preferences, standing extra steps):
|
|
101
|
+
pass `"scope": "operator:local"`. Every project's recall includes the
|
|
102
|
+
operator scope, so the memory follows the user everywhere. Never pin an
|
|
103
|
+
operator memory to one project.
|
|
104
|
+
|
|
105
|
+
## Step 3b — standing rules go to review as policy proposals
|
|
106
|
+
|
|
107
|
+
A rule the user stated for the work ("always use X", "never do Y", "the
|
|
108
|
+
convention is Z") is enforceable: a reviewer can judge a change against it.
|
|
109
|
+
That makes it steering, and steering is approved by a person before it
|
|
110
|
+
applies. Do not write it as a memory. File one proposal per rule through the
|
|
111
|
+
estate shim's `propose` action (the review queue; nothing applies until the
|
|
112
|
+
user approves it):
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
wicked-garden run scripts/_estate_client.py --readonly propose '{"kind_type":"policy:development","payload":{"rule":"<imperative: what must hold>","severity":"warn","capture":"rule","reach":"operator"},"facets":{"project":"<project>"}}'
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
- `kind_type` is `policy:<type>`, with `<type>` exactly one of
|
|
119
|
+
`architecture`, `development`, `security`, `testing`, `operations`,
|
|
120
|
+
`compliance` or `design-ux`.
|
|
121
|
+
- `severity` is exactly one of `info`, `warn`, `error` or `critical`.
|
|
122
|
+
- `reach` says where the rule applies. A rule the user states is theirs
|
|
123
|
+
for **every** project: `"reach": "operator"`. Use `"reach": "project"`
|
|
124
|
+
only when they named this project or one of its repos (add `repo` to the
|
|
125
|
+
facets for a repo). The reviewer sees the reach and can change it; never
|
|
126
|
+
leave it out.
|
|
127
|
+
- `facets.project` is required (the shim refuses a proposal without it). It
|
|
128
|
+
records where the rule was said; with `"reach": "operator"` it does not
|
|
129
|
+
narrow the rule.
|
|
130
|
+
- Never pass `provenance`.
|
|
131
|
+
|
|
132
|
+
Store a pointer memory only when the *reason* for the rule is worth
|
|
133
|
+
recalling on its own ("we ban X because incident Y"). The rule itself lives
|
|
134
|
+
in the proposal. If the shim answers `ok: false`, report the rule text and
|
|
135
|
+
the degrade; never fall back to storing it as a memory.
|
|
85
136
|
|
|
86
137
|
## Step 4 — batch write
|
|
87
138
|
|
|
@@ -90,7 +141,8 @@ One backend call, JSON on stdin (never argv — summaries contain quotes):
|
|
|
90
141
|
```bash
|
|
91
142
|
printf '%s' '{"memories":[
|
|
92
143
|
{"content":"<summary 1>","kind":"fact","about":["tag1","tag2"]},
|
|
93
|
-
{"content":"<summary 2>","kind":"skill","about":["tag3"]}
|
|
144
|
+
{"content":"<summary 2>","kind":"skill","about":["tag3"]},
|
|
145
|
+
{"content":"<how the user works>","kind":"fact","about":["style"],"scope":"operator:local"}
|
|
94
146
|
]}' | wicked-garden run \
|
|
95
147
|
scripts/mem/estate_memory.py capture-batch -
|
|
96
148
|
```
|
|
@@ -112,6 +164,7 @@ wicked-garden run \
|
|
|
112
164
|
## Step 6 — report
|
|
113
165
|
|
|
114
166
|
- `{N} memories stored` (+ `{K} failed` if any, with each refusal reason), with kinds
|
|
167
|
+
- `{P} rules proposed for review` (Step 3b), with each proposal id
|
|
115
168
|
- one-line topic list
|
|
116
169
|
- if estate was unreachable (`ok: false`): report the degrade explicitly so
|
|
117
170
|
the learnings can be re-captured later — never claim success on a
|
|
@@ -216,10 +216,10 @@ wicked-garden run scripts/qe/lib/gate.mjs \
|
|
|
216
216
|
```
|
|
217
217
|
|
|
218
218
|
- **Release dependency:** needs the wicked-vault **manifest-2.1 twin**
|
|
219
|
-
(`validateManifest` + `CLAIM_LEVELS`)
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
219
|
+
(`validateManifest` + `CLAIM_LEVELS`), which shipped in wicked-vault 0.7.0;
|
|
220
|
+
garden's floor is **0.8.0**. An older vault is refused fail-closed, never
|
|
221
|
+
silently degraded — upgrade with `npm i -g wicked-vault@latest` (or set
|
|
222
|
+
`WICKED_QE_VAULT_PKG` to point at a specific 0.8.0+ install).
|
|
223
223
|
|
|
224
224
|
## Wiring context
|
|
225
225
|
|
|
@@ -279,7 +279,7 @@ Rules, all fail-closed:
|
|
|
279
279
|
3. **Grades are opinions, not re-derivable facts**: `attest` appends, never
|
|
280
280
|
edits; the vault refuses a self-grade (evaluator = recording actor) and
|
|
281
281
|
a grade over a tampered artifact.
|
|
282
|
-
4. **Release dependency**: needs the wicked-vault manifest-2.1 twin
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
282
|
+
4. **Release dependency**: needs the wicked-vault manifest-2.1 twin
|
|
283
|
+
(shipped in wicked-vault 0.7.0; garden's floor is **0.8.0**). An older
|
|
284
|
+
vault is refused fail-closed — upgrade with `npm i -g wicked-vault@latest`
|
|
285
|
+
(or set `WICKED_QE_VAULT_PKG` to point at a specific 0.8.0+ install).
|
|
@@ -4,7 +4,7 @@ description: |
|
|
|
4
4
|
Learn an unfamiliar repo the way a senior engineer does: follow where the code
|
|
5
5
|
actually churns, find what that churn touches that the rest of the system leans
|
|
6
6
|
on, read the load-bearing code for real, then write down BOTH what you learned
|
|
7
|
-
(
|
|
7
|
+
(knowledge) and what should hold (policies) — as inert estate proposals a human
|
|
8
8
|
reviews, never as asserted fact.
|
|
9
9
|
|
|
10
10
|
Three BOUNDED phases, one wicked-crew unit each: (1) CHURN — sampled git churn →
|
|
@@ -28,8 +28,8 @@ metadata:
|
|
|
28
28
|
A repo teaches you where to look if you follow two independent signals at once:
|
|
29
29
|
**temporal** (where the code churns) and **structural** (what the rest of the system
|
|
30
30
|
depends on). This skill walks the intersection, reads it for real, and **captures the
|
|
31
|
-
learning back** as estate proposals —
|
|
32
|
-
hold). Garden ORCHESTRATES; estate GROUNDS (graph + read) and RECEIVES (the proposal
|
|
31
|
+
learning back** as estate proposals — knowledge (what is true, read from the code) and
|
|
32
|
+
policies (what should hold); a memory only for what you witnessed or were told. Garden ORCHESTRATES; estate GROUNDS (graph + read) and RECEIVES (the proposal
|
|
33
33
|
queue); a human APPROVES — every capture is an inert proposal the studio Memories /
|
|
34
34
|
Policies surfaces review, never an asserted fact.
|
|
35
35
|
|
|
@@ -97,7 +97,7 @@ Churn and centrality answer different questions; the intersection ranks targets.
|
|
|
97
97
|
|
|
98
98
|
| | **High churn** | **Low churn** |
|
|
99
99
|
|-----------------------|----------------|---------------|
|
|
100
|
-
| **High centrality** | load-bearing + volatile → **read deeply**; likely yields BOTH
|
|
100
|
+
| **High centrality** | load-bearing + volatile → **read deeply**; likely yields BOTH knowledge (how it works / why it moves, read from the code) AND a policy (what must hold as it changes) | stable core → **read for invariants**; yields policies (severity `error`/`critical`) more than knowledge |
|
|
101
101
|
| **Low centrality** | churny periphery (config, fixtures, generated) → **mostly noise**; skip unless it's a hot integration seam | quiet leaf → **skip** |
|
|
102
102
|
|
|
103
103
|
The prime targets are the top-left cell: paths that appear in BOTH the phase-1
|
|
@@ -148,18 +148,21 @@ when the proposal is approved, so the learning is lost):
|
|
|
148
148
|
knowledge. `kind_type: "memory"`; payload
|
|
149
149
|
`{"content": "<1–3 sentences>", "tier": "<value>"}` where `tier` is EXACTLY one
|
|
150
150
|
of `working` / `episodic` / `semantic` / `procedural` / `archival` — for a repo
|
|
151
|
-
learning use `semantic` (a
|
|
152
|
-
NEVER invent a tier like `durable`.
|
|
151
|
+
learning use `semantic` (a decision or gotcha) or `procedural` (a how-to you were
|
|
152
|
+
taught); NEVER invent a tier like `durable`. A convention or rule the team must
|
|
153
|
+
follow ("our convention is always X") is a **policy**, never a memory. Facets `{"repo": "<name>", "project": "<name>"}`.
|
|
153
154
|
- **Policy** — what *should hold*. `kind_type: "policy:<type>"` where `<type>` ∈
|
|
154
155
|
architecture · development · security · testing · operations · compliance ·
|
|
155
|
-
design-ux; payload `{"rule": "<imperative>", "severity": "<value>"}`
|
|
156
|
+
design-ux; payload `{"rule": "<imperative>", "severity": "<value>", "reach": "project"}`
|
|
157
|
+
(a rule learned from this repo applies to its project) where
|
|
156
158
|
`severity` is EXACTLY one of `info` / `warn` / `error` / `critical` — the middle
|
|
157
159
|
band is `warn`, NOT `warning`. Facets `{"repo": "<name>", "project": "<name>", "language": "<lang>"}`.
|
|
158
160
|
- **Never pass `provenance`** — the server stamps it from `WICKED_RUN_*`. Passing
|
|
159
161
|
it is at best ignored; treat provenance as not yours to set.
|
|
160
|
-
- Derive **both** per target where the 2×2 warrants it: the
|
|
161
|
-
*is*, the policy
|
|
162
|
-
policy; a "this is how X actually wires up" discovery
|
|
162
|
+
- Derive **both** per target where the 2×2 warrants it: the knowledge record
|
|
163
|
+
holds the *is*, the policy holds the *ought*. A stable high-centrality
|
|
164
|
+
invariant is a policy; a "this is how X actually wires up" discovery was read
|
|
165
|
+
from the code, so it is knowledge, never a memory.
|
|
163
166
|
|
|
164
167
|
## In a governed run
|
|
165
168
|
|
|
@@ -187,7 +190,7 @@ default; the shim refuses an unpinned store — report that, never guess one.
|
|
|
187
190
|
call, no variants, no wrappers (governed-worker A2/A5). The read-only CLI is still
|
|
188
191
|
allowed by the fence but is not a documented rung.
|
|
189
192
|
2. **Capture** (phase 3) submits each proposal through the shim —
|
|
190
|
-
`wicked-garden run scripts/_estate_client.py --readonly propose '{"kind_type":"
|
|
193
|
+
`wicked-garden run scripts/_estate_client.py --readonly propose '{"kind_type":"knowledge","payload":{…},"facets":{…}}'`
|
|
191
194
|
(`proposal.submit`; provenance is server-stamped from the `WICKED_RUN_*` markers on your
|
|
192
195
|
environment, never passed). **There is no deliverable file and no file fallback**: write
|
|
193
196
|
nothing into the repository (governed-worker E1) and nothing elsewhere either. If the shim
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Capture — memories AND policies as estate proposals
|
|
1
|
+
# Capture — knowledge, memories AND policies as estate proposals
|
|
2
2
|
|
|
3
3
|
The learning phase ends by writing back records through the estate
|
|
4
4
|
**`proposal.submit`** tool (reached through the estate shim): **knowledge** (how the
|
|
@@ -17,7 +17,7 @@ the record; a human promotes it.
|
|
|
17
17
|
|
|
18
18
|
| Field | Type | Rule |
|
|
19
19
|
|-------|------|------|
|
|
20
|
-
| `kind_type` | string | `"memory"` OR `"policy:<type>"`; must match `^[a-z][a-z0-9_-]*(:[a-z][a-z0-9_-]*)?$` |
|
|
20
|
+
| `kind_type` | string | `"knowledge"`, `"memory"` OR `"policy:<type>"`; must match `^[a-z][a-z0-9_-]*(:[a-z][a-z0-9_-]*)?$` |
|
|
21
21
|
| `payload` | JSON **object** | required; a present non-object is rejected `-32602` (never silently defaulted) |
|
|
22
22
|
| `facets` | JSON object of `axis:value` strings | each axis is a lowercase token `^[a-z][a-z0-9_-]*$`, each value non-empty; `project` is **required** (the shim refuses a proposal without it) |
|
|
23
23
|
|
|
@@ -36,7 +36,7 @@ The estate shim reaches `proposal.submit` without an MCP server being registered
|
|
|
36
36
|
with your harness, on every seat CLI:
|
|
37
37
|
|
|
38
38
|
```bash
|
|
39
|
-
wicked-garden run scripts/_estate_client.py --readonly propose '{"kind_type":"
|
|
39
|
+
wicked-garden run scripts/_estate_client.py --readonly propose '{"kind_type":"knowledge","payload":{"content":"…","class":"concept","source":"<repo>:<path>","source_rev":"<sha>"},"facets":{"repo":"<name>","project":"<name>"}}'
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
`--readonly` is literal (the shim spawns `wicked-estate-mcp --readonly`; `proposal.submit`
|
|
@@ -45,8 +45,9 @@ is the safe write it still permits). The store is pinned from the worker environ
|
|
|
45
45
|
unpinned store is refused with `{"ok": false, "reason": …}` — report it, do not guess a
|
|
46
46
|
store. The shim answers `{"ok": true, "id": "<proposal-id>"}` or `{"ok": false,
|
|
47
47
|
"reason": …, "code": <json-rpc code or null>}`: `-32602` is a *your-args* bug (fix the
|
|
48
|
-
shape), `null` means the estate was unreachable (keep the objects — next section).
|
|
49
|
-
JSON
|
|
48
|
+
shape), `null` means the estate was unreachable (keep the objects — next section). Pass
|
|
49
|
+
the JSON as ONE quoted argument, even when it is long: `propose` does not read stdin. A
|
|
50
|
+
`provenance` key is dropped.
|
|
50
51
|
|
|
51
52
|
### When `propose` fails in a governed run — no file fallback
|
|
52
53
|
|
|
@@ -113,10 +114,11 @@ implementation fails closed" is knowledge.
|
|
|
113
114
|
- `content` — distilled, self-contained: the *why* and *what* a future session
|
|
114
115
|
needs, not a paragraph of *how*. One to three sentences. If it needs the current
|
|
115
116
|
file open to make sense, it isn't distilled yet.
|
|
116
|
-
- `tier` — `"semantic"` for
|
|
117
|
-
bus
|
|
118
|
-
|
|
119
|
-
|
|
117
|
+
- `tier` — `"semantic"` for a decision or gotcha you witnessed or were told
|
|
118
|
+
("the bus path was chosen over a direct call because direct calls dropped
|
|
119
|
+
events in incident X"); `"procedural"` for a how-to you were taught. How the
|
|
120
|
+
code is wired ("X is wired via the bus") was read from the code: that is a
|
|
121
|
+
`knowledge` proposal, not a memory.
|
|
120
122
|
- `facets` — `repo:` and `project:` locate the memory so faceted recall admits it
|
|
121
123
|
for the right work. Use the repo's directory/remote name and the umbrella
|
|
122
124
|
project (here, `wicked`). **`project:` is required** on every proposal,
|
|
@@ -133,7 +135,7 @@ implementation fails closed" is knowledge.
|
|
|
133
135
|
```json
|
|
134
136
|
{
|
|
135
137
|
"kind_type": "policy:architecture",
|
|
136
|
-
"payload": { "rule": "<imperative statement of what must hold>", "severity": "error" },
|
|
138
|
+
"payload": { "rule": "<imperative statement of what must hold>", "severity": "error", "reach": "project" },
|
|
137
139
|
"facets": { "repo": "<repo-name>", "project": "<project-name>", "language": "<lang>" }
|
|
138
140
|
}
|
|
139
141
|
```
|
|
@@ -142,6 +144,9 @@ implementation fails closed" is knowledge.
|
|
|
142
144
|
a diff against it ("Every emitted Edge carries {confidence, provenance,
|
|
143
145
|
resolved_by}"; "No content-hash or line-number node ids"). Not a description —
|
|
144
146
|
a *ought*.
|
|
147
|
+
- `reach` — `"project"`: a rule learned from this repo applies to this
|
|
148
|
+
repo's project. (`"operator"` = every project is for rules the operator
|
|
149
|
+
states, not for what a repo teaches.)
|
|
145
150
|
- `severity` — `info` (advisory) · `warn` (should) · `error` (must; a violation
|
|
146
151
|
blocks) · `critical` (must; a violation is a security/data-loss class). Map from
|
|
147
152
|
the 2×2 below and from what the code's own guardrails signal.
|
|
@@ -156,16 +161,17 @@ proposal a read target warrants:
|
|
|
156
161
|
|
|
157
162
|
| Cell | Signal | Propose |
|
|
158
163
|
|------|--------|---------|
|
|
159
|
-
| **high churn + high centrality** | load-bearing and moving | **BOTH**:
|
|
160
|
-
| **low churn + high centrality** | stable core / invariant | mostly **policy** (`error`/`critical`) capturing the invariant; add
|
|
161
|
-
| **high churn + low centrality** | churny periphery | usually **neither**;
|
|
164
|
+
| **high churn + high centrality** | load-bearing and moving | **BOTH**: knowledge (how it works / what it wires, read from the code) + a policy (the invariant that must survive the churn — often `error`) |
|
|
165
|
+
| **low churn + high centrality** | stable core / invariant | mostly **policy** (`error`/`critical`) capturing the invariant; add knowledge only if the *why* is non-obvious from the code, and a memory only if the operator told you the why |
|
|
166
|
+
| **high churn + low centrality** | churny periphery | usually **neither**; knowledge only if it's a hot integration seam worth flagging (e.g. "config X is edited every release — treat as an interface") |
|
|
162
167
|
| **low churn + low centrality** | quiet leaf | **skip** |
|
|
163
168
|
|
|
164
|
-
The discipline:
|
|
165
|
-
records the **ought** (this is what a change must
|
|
166
|
-
target frequently yields one of each — the
|
|
167
|
-
|
|
168
|
-
|
|
169
|
+
The discipline: knowledge records the **is** (this is how the system is, read
|
|
170
|
+
from the code), a policy records the **ought** (this is what a change must
|
|
171
|
+
preserve). A single load-bearing target frequently yields one of each — the
|
|
172
|
+
knowledge so the next reader understands it, the policy so the next editor
|
|
173
|
+
doesn't break it. A memory is only for what you witnessed or were told.
|
|
174
|
+
Do not force a proposal from a cell that says skip; a thin capture pollutes the queue the operator must triage.
|
|
169
175
|
|
|
170
176
|
## Worked examples
|
|
171
177
|
|
|
@@ -191,7 +197,8 @@ Policy (architecture, from the same subsystem's invariant):
|
|
|
191
197
|
"kind_type": "policy:architecture",
|
|
192
198
|
"payload": {
|
|
193
199
|
"rule": "Every emitted Edge must carry {confidence, provenance, resolved_by}; never present a heuristic edge as a fact.",
|
|
194
|
-
"severity": "error"
|
|
200
|
+
"severity": "error",
|
|
201
|
+
"reach": "project"
|
|
195
202
|
},
|
|
196
203
|
"facets": { "repo": "wicked-estate", "project": "wicked", "language": "rust" }
|
|
197
204
|
}
|
|
@@ -204,7 +211,8 @@ Policy (development, language-scoped, from a stable core with a clear guardrail)
|
|
|
204
211
|
"kind_type": "policy:development",
|
|
205
212
|
"payload": {
|
|
206
213
|
"rule": "Rust: no bare panic!/unwrap in library crates; surface a typed error.",
|
|
207
|
-
"severity": "warn"
|
|
214
|
+
"severity": "warn",
|
|
215
|
+
"reach": "project"
|
|
208
216
|
},
|
|
209
217
|
"facets": { "repo": "wicked-estate", "project": "wicked", "language": "rust" }
|
|
210
218
|
}
|
|
@@ -41,9 +41,10 @@ every project, on explicit request); `--budget <tokens>`
|
|
|
41
41
|
`[knowledge · src docs/adr/0005.md]` or
|
|
42
42
|
`[memory · fact · 2026-10-10 · project:wicked-garden]`, so the reader
|
|
43
43
|
sees which side it came from and how old it is
|
|
44
|
-
- on conflict, an
|
|
45
|
-
the source (knowledge) governs what *does
|
|
46
|
-
|
|
44
|
+
- on conflict, an approved steering rule (estate `rules.recall`) governs
|
|
45
|
+
what *should* hold and the source (knowledge) governs what *does*; a
|
|
46
|
+
memory says what was decided or told and why, not what is enforced.
|
|
47
|
+
Show the disagreement, never pick silently by date
|
|
47
48
|
|
|
48
49
|
End with a `Sources:` list — every distinct `source` / scope used, so
|
|
49
50
|
the reader can verify each claim.
|