Classify every gap and rank the work (V-725)

Session 2 step 3, and the end of the explanation half.

gaps.md compares responsibilities and never package names. Eight classes. The
four capability classes are derived from the ledger's gap_class field and
rebuild with build_ledger.py. The four architecture classes are read from
findings.md and invariants.md, and every entry names the capability or invariant
it affects. An entry naming neither is marked non-blocking cleanup in those
words, which is the whole of class 8 and its eleven rows.

Of 46 v1 capabilities: 5 missing, 21 partial and reachable, 9 built and
unreachable, 11 reachable and unverified.

The nine unreachable ones are seven config blocks and two compose entries. Not
one is a code defect.

The ranked list puts phrasing first: speak-as-herself fails all three criteria,
and everything that asks the resident model to write a Russian sentence inherits
that. His own name not being stored is second. Nine capabilities one config
change from reachable is fourth, and it is the highest ratio of capability to
work in the list.

Items 10, 12 and 13 stall on unresolved invariants and are the owner's call, not
work.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-26 12:44:15 +04:00
parent 41c97bba8d
commit 8153e5eaa5
4 changed files with 310 additions and 1 deletions
+2
View File
@@ -20,6 +20,8 @@ whole directory is built against.
| `probes_dod.json` | probes derived from the ledger's criteria | no, generated |
| `run_probes.py` | drives a probe file through the deployed stack | yes |
| `store_counts.py` | row counts per store, over IPC | yes |
| `invariants.md` | the twelve cross-cutting rules the 51 capabilities imply | yes |
| `gaps.md` | eight gap classes and the one ranked priority list | yes, except classes 1-4 |
| `out/` | raw probe output, one JSON object per line | no |
## Rebuilding
+16 -1
View File
@@ -263,7 +263,7 @@ def emit(caps, section_notes, domains, verdicts, impl, arch):
dims = dimensions(c, impl.get(c["id"], []), arch, verdicts)
L.append(" implementation:")
for k in ("designed", "code_present", "wired", "configured",
"deployed", "reachable", "verified"):
"deployed", "reachable", "verified", "gap_class"):
# Quoted: bare yes/no are YAML booleans and the
# round-trip check reads them back as True/False.
L.append(f" {k}: {dims[k]!r}")
@@ -364,6 +364,18 @@ def dimensions(cap, comps, arch, verdicts):
vs = [verdicts.get(cr["id"], {}).get("verified", "untested")
for cr in cap["criteria"]]
# The gap class, for docs/capabilities/gaps.md. Order matters: nothing built
# outranks nothing reachable, which outranks something reachable and wrong.
if out["code_present"] == "no":
out["gap_class"] = "capability missing"
elif out["reachable"] != "yes":
out["gap_class"] = "capability exists but unreachable"
elif any(v == "fail" for v in vs):
out["gap_class"] = "capability partial"
elif all(v == "pass" for v in vs):
out["gap_class"] = "none"
else:
out["gap_class"] = "capability exists but unverified"
if vs and all(v == "pass" for v in vs):
out["verified"] = "yes"
elif any(v == "pass" for v in vs):
@@ -526,6 +538,9 @@ def main():
if d_["code_present"] == "no" and d_["verified"] != "no":
print(f" ANOMALY {c['id']}: nothing carries it and it scores "
f"verified={d_['verified']} (a negative criterion passing by absence)")
t = _C(dimensions(c, impl.get(c["id"], []), arch, verdicts)["gap_class"]
for c in caps if c["scope"] == "v1")
print(" v1 gap classes: " + ", ".join(f"{a} {n}" for a, n in sorted(t.items())))
used = {x for v in impl.values() for x in v}
orphan = sorted(set(arch) - used)
print(f" components serving no capability: {len(orphan)}")
+241
View File
@@ -0,0 +1,241 @@
# Gaps: what is missing, and what the architecture does about it
Hand-written, except the four capability classes, which are derived.
This file compares responsibilities. It never compares package names. A package
existing is not a capability, and a capability can be spread over six packages
and still be missing.
## Where each class comes from
Classes 1 through 4 are the `gap_class` field in `docs/capabilities/ledger.yaml`,
derived from the seven implementation dimensions and the criteria verdicts.
Rebuild them:
```sh
python3 docs/capabilities/build_ledger.py
```
Classes 5 through 8 are read from `docs/architecture/findings.md` and
`docs/capabilities/invariants.md`. **Every entry names the capability or
invariant it affects.** An entry affecting neither is marked non-blocking
cleanup, in those words, and it is the whole of class 8.
Counts are over the 46 v1 capabilities. The 5 deferred ones are excluded.
---
## 1. Capability missing (5)
Nothing carries it. `code_present: no`.
| capability | criteria | note |
| --- | --- | --- |
| `summaries` | 0 pass, 3 fail | no package. Wanted by `email-triage`, `web-crawling`, `hearing` and `rss-and-news`, each of which would consume it |
| `webhooks` | 0 pass, 3 fail | no package. Telegram's own inbound channel is mapped to `telegram`, not here |
| `command-chaining` | 0 pass, 3 fail | no package. The `chain` in `internal/router` is the world chain and the source chain |
| `learning-the-style` | 1 pass, 2 fail | the pass is a negative criterion satisfied by absence. The build reports it as an anomaly |
| `learning-from-mistakes` | 0 pass, 2 fail | no package |
The last two are invariant 10, and it is `unresolved`. Whether behavioural
learning is wanted is a product question, so these two are not automatically
work.
## 2. Capability partial (21)
Reachable, and at least one criterion was observed failing. This is the class
that matters most, because a user can get to all 21 today and 21 misbehave.
`route-an-utterance`, `ask-instead-of-guessing`, `answer-from-your-own-data`,
`answer-from-the-world`, `read-an-encyclopedia`, `facts`, `notes`, `recall`,
`reminders`, `voice`, `web-ui`, `desk-notifications`, `wake-word`, `nexus`,
`praxis`, `the-deployed-stack`, `encrypted-database`, `passkey-and-step-up`,
`tests-and-analyzers`, `web-crawling`, `cron-jobs`.
`wake-word` is the sharpest: reachable on every dimension and 0 of 2 criteria
pass.
## 3. Capability exists but unreachable (9)
Built, and the deployed configuration does not reach it.
| capability | why | class of fix |
| --- | --- | --- |
| `speak-as-herself` | `reachable: partial` on `core.model_seam` | configuration |
| `weather` | no `weather` key in the deployed `voice` block | configuration |
| `see-an-image` | no media block | configuration |
| `memory-evaluation` | worker is `configured-off` | configuration |
| `ntfy` | present in the config and disabled there | configuration |
| `hearing` | `capture.enabled` false and no capture client ships (V-514) | configuration and code |
| `mcps` | no MCP server configured, and V-478 blocks the one candidate | deployment |
| `email-triage` | `mavmaild` is not in `docker-compose.yml` | deployment |
| `calendar-management` | `mavcaldav` is not in `docker-compose.yml` | deployment |
None of these nine is a code defect. Seven are one config block and two are one
compose entry. `docs/spec.md` says this about the audit's four and it still
holds for these nine.
## 4. Capability exists but unverified (11)
Reachable, nothing observed failing, and not all criteria pass. These are
measurement gaps, not defects.
`interruption-policy`, `digest-of-held-nudges`, `morning-routine`,
`routine-proposals`, `tasks`, `rss-and-news`, `telegram`, `speech-to-text`,
`text-to-speech`, `hexis`, `network-scans`.
Four of them, the whole Proactive cluster, are untested on every criterion,
because a proactive behaviour cannot be probed by sending an utterance. That is
the shape of the gap and it needs a different harness, not more probes.
---
## 5. Duplicated mechanism (6)
| what | affects | owned? |
| --- | --- | --- |
| Two independent arbitrations decide one turn: seven intents, then twenty-two ordered query sources (`findings.md` 2.1) | invariant 11, `route-an-utterance`, `answer-from-your-own-data` | no |
| A third arbitration runs before both: eleven stateful pre-emptors in the pre-route ladder (`findings.md` 2.2) | invariant 11, invariant 6, `ask-instead-of-guessing` | no |
| Two tier systems. `internal/auth` does not bind the turn path, `internal/tool` is not keyed on the reach (`findings.md` 6.3, 6.3b) | invariant 8, `hexis`, `passkey-and-step-up` | no |
| Two representations of reach, both ignored (`findings.md` 6.3) | invariant 8, `voice` | no |
| Two digest mechanisms with the same word in the name, flushed six lines apart (`findings.md` 2.4) | invariant 5, `digest-of-held-nudges` | no |
| Restraint decided twice: the gate decides whether a rule emits, delivery decides where it lands (`findings.md` 2.3) | `interruption-policy` | **yes**, argued in `channel.go` |
The last row is duplication that is owned. It is listed so it is not
rediscovered as a defect.
## 6. Missing shared mechanism (6)
| what is missing | affects |
| --- | --- |
| A single point that decides whether this origin may perform this effect with this evidence. `origin × effect × evidence → permit` is the target and nothing computes it | invariant 8, `hexis`, `praxis`, `voice`, `passkey-and-step-up` |
| An owner for a key namespace. `facts` has nine writers, `notes` six, `tools` three unrelated proposers (`findings.md` 1.1, 1.2, 1.3) | invariant 2, `facts`, `notes`, `recall` |
| A comparable unit of evidence, so claimants can answer "is this more mine than yours?". `internal/claim` is that unit, written, tested and called by nothing (`findings.md` 6.1) | invariant 11, `command-chaining` |
| A conversation that spans reaches. `mavweb` instead hardcodes one conversation id for the whole web reach | invariant 1, `web-ui`, `voice`, `telegram` |
| A stated rule for what survives a restart. Six stores, six independent choices, two of them argued | invariant 12, `ask-instead-of-guessing` |
| A summariser. Four capabilities would consume one and none exists | `summaries`, `email-triage`, `web-crawling`, `hearing` |
## 7. Current architecture conflicts with target behavior (10)
The class where the code works as written and the written thing is not what the
spec asks for.
| conflict | affects |
| --- | --- |
| Four silent degradations stack on one turn, and `docs/spec.md` writes every v1 DoD at "honest" (`findings.md` 8.1) | invariant 7, `answer-from-the-world`, `speech-to-text`, `route-an-utterance`, `speak-as-herself` |
| `praxisItemAction.handle` calls straight through: acknowledge, resolve, ignore and pin run on first hearing with no tier and no confirm turn (`findings.md` 6.3c, `cmd/mavend/ecosystem_acts.go:158`) | invariant 8, `praxis` |
| `weather` is a live query source with `guesses: true` and the deployed config selects no provider, so it can claim a turn and answer from a stub (`findings.md` 11.3) | invariant 7, `weather` |
| `loop.State.CalendarBusy` reads facts `mavcaldav` never writes, so the do-not-nag-mid-meeting suppressor is permanently false (`findings.md` 8.2) | invariant 3, `interruption-policy`, `calendar-management` |
| Recurring reminders have a column, an IPC parameter and no caller. `actionReminder` passes `""` (`findings.md` 8.3) | `reminders`, `cron-jobs` |
| The clarify store is not persisted and the expired-clarify notice reads the store that is gone (`findings.md` 7.5) | invariant 6, invariant 12, `ask-instead-of-guessing` |
| `Claim.Coverage` returns 1.0 for a claim that extracted nothing (`findings.md` 6.3d) | invariant 11. Latent: it corrupts the fix for class 6 row 3 before that fix ships |
| The act executor runs inside the key holder, and the process boundary is not one of the controls (`findings.md` 5.4) | invariant 8, `hexis`, `encrypted-database` |
| The voice wire's whole security argument is external: loopback publish plus an ssh tunnel, so one compose edit removes it (`findings.md` 5.5) | invariant 8, `voice` |
| `make test` is green with the four `TestONNX*` measurements silently skipped, because the recipe does not set `MAVEN_ONNX_LIB` | `tests-and-analyzers`, `recall`. It is why the predecessor audit had a green suite and 22 dead capabilities |
## 8. Architecture concern with no current product impact (11)
**Every row here is non-blocking cleanup.** None names a capability or an
invariant, which is the test for belonging in this class rather than in 5, 6 or
7.
- `reactiveHandler` has 34 fields (`findings.md` 4.1).
- `runTurn` is one function with eleven early returns (4.2).
- `tick` runs thirteen jobs in one function (4.3).
- `wireVoice` is one constructor for seventeen subsystems (4.4).
- `mavsttd` and `mavttsd` are separate processes at a scale that does not need it (5.1).
- Three IPC connections from one process (5.2).
- A construction cycle between the API layer and the turn layer (3.1).
- The handler holds the raw store beside the mediated one (3.2).
- `queryDayPlan` reads the proactive scheduler, the single call across that line (3.4).
- `internal/modes` is imported by nothing outside itself (6.2).
- The daemon is wired twice, in two places (8.6).
Two entries were considered for this class and moved out. `queryNetwork`
triggering a live LAN scan inside a read path (6.4) affects `network-scans`,
whose two remaining criteria are `unknown`. `actionFact` re-routing into the
query chain (6.5) affects `facts` and `route-an-utterance`, which is where the
"меня зовут Ками" misroute lives.
---
# Priority
One list. The rank is the plan's, and it is about impact today, not about how
ugly the code is. An unwired or unreachable future defect never outranks a live
user-visible failure because its architecture is offensive.
## 1. Prevents intended everyday use today
1. **`speak-as-herself` fails all three criteria.** The deployed resident model,
`maven-instruct-b2-Q4_K_XL`, produces Russian sentences that no longer hold
together, and the phrasing checks that would catch it run in the eval and not
on the outbound path. Everything that asks the model to write a sentence
inherits this. Formal `вас` and `вы` reached the wire while `CheckFeminine`
passed.
2. **His own name is not stored as a fact.** "меня зовут Ками" routes to chat,
so nothing is written, and "что ты помнишь обо мне?" routes to chat too.
Two of the seven audit probes, still broken and now broken differently.
3. **`wake-word` fails both criteria while reachable on every dimension.** Voice
is the spine of v1 and the always-on half of it does not work.
4. **Nine capabilities are one config block or one compose entry from
reachable.** `weather`, `ntfy`, `see-an-image`, `memory-evaluation`,
`email-triage`, `calendar-management` and `mcps` are the cheap ones. This is
the highest ratio of capability to work in the whole list.
## 2. Makes existing behavior incorrect or unreliable
5. **The Praxis lifecycle path has no gate.** Four remote mutations run on first
hearing. This is live today and needs no new wiring to matter.
6. **`weather` answers from a stub and is allowed to claim the turn.** A source
marked `guesses: true` with no provider is worse than a named gap.
7. **The busy suppressor is permanently false.** Every interruption decision
that should have deferred to a meeting fails open.
8. **Four silent degradations stack**, and nothing in a reply distinguishes the
worst case from the best. Invariant 7 has no written boundary between "only
better" and "cannot do the job".
9. **A parked clarify survived five consecutive turns** and was released by a
path other than `отмена`. Invariant 6 says nobody owns closing it.
## 3. Blocks multiple capabilities
10. **No single authorization point.** Invariant 8, `unresolved`, and the third
of the three questions the freeze was called to answer. It blocks `hexis`,
`praxis`, `voice` and `passkey-and-step-up`, and it is the one property
nobody can currently state.
11. **No owner for a key namespace.** A fetch watermark and a tuning parameter
live in the table recall embeds and `queryFactByKey` reads back as an
answer.
12. **No comparable unit of evidence.** Three ordered lists decide one turn.
`command-chaining` cannot be built on top of them, and `internal/claim`
carries a live defect before it is wired.
13. **No summariser.** Four capabilities would consume one.
## 4. Prevents verification
14. **`make test` is green with four measurements skipped.** The recipe does not
set `MAVEN_ONNX_LIB`. This is the exact trap `CLAUDE.md` describes, and the
baseline walked into it while measuring whether other things had.
15. **The whole Proactive cluster is untested on every criterion.** A proactive
behaviour cannot be probed by sending an utterance. It needs a clock-driving
harness, not more probes.
16. **26 of 31 named scenarios do not exist on disk.** Only 5 of 51 spec entries
cite a scenario that is there (`findings.md` 9.5).
17. **`POST /api/ptt` was called unreachable in an earlier draft and is not.**
Four speech criteria were filed `deployment missing` when the deployment is
present and the probe was never written.
## 5. Architectural cleanup with no present user impact
18. Everything in class 8, in any order. None of it blocks a capability or an
invariant, and that is why it is last.
---
## What this file does not do
It does not schedule. `docs/roadmap.md` orders the work and this file feeds it.
It does not decide the four `unresolved` invariants. Authority and confirmation,
learning from outcomes, capability composition and the shelf life of a held
nudge are the owner's, and items 10, 12 and 13 above stall on them.
+51
View File
@@ -34,6 +34,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'partial'
gap_class: 'capability partial'
components: [router.cascade, router.stage0, router.heads, router.llm, router.classifier, router.embedder, router.extractor, core.turn_route, core.topics, core.decision_trace, state.decision_ring, state.routing_traces, state.routing_labels]
scenarios:
- name: conversation_anaphora
@@ -96,6 +97,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'partial'
gap_class: 'capability partial'
components: [core.preroute, state.clarify_store, state.dialogue_sessions]
scenarios:
- name: conversation_anaphora
@@ -147,6 +149,7 @@ capabilities:
deployed: 'partial'
reachable: 'partial'
verified: 'no'
gap_class: 'capability exists but unreachable'
components: [core.phraser, core.replier, core.action_chat, core.model_seam, svc.llama_server, eval.phrasing]
scenarios:
- name: morning_missed
@@ -199,6 +202,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'partial'
gap_class: 'capability partial'
components: [core.query_chain, core.q.embed, core.q.memory, core.q.factbykey, core.q.notes, core.q.history, core.q.list, core.q.self, core.q.personal, state.list_items]
scenarios:
- name: assistant_workday
@@ -251,6 +255,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'no'
gap_class: 'capability partial'
components: [core.q.search, core.q.web, core.q.general, core.q.personal, ext.searxng]
scenarios:
- name: world_summary_quality
@@ -301,6 +306,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'no'
gap_class: 'capability partial'
components: [core.q.kiwix, ext.kiwix]
scenarios:
- name: kiwix_language_pick
@@ -351,6 +357,7 @@ capabilities:
deployed: 'partial'
reachable: 'partial'
verified: 'no'
gap_class: 'capability exists but unreachable'
components: [core.q.weather, ext.openmeteo]
finding: >-
the provider seam, the home city and the clarify path have no written reasoning anywhere. The audit found the capability broken on configuration alone.
@@ -413,6 +420,7 @@ capabilities:
deployed: 'no'
reachable: 'no'
verified: 'no'
gap_class: 'capability exists but unreachable'
components: [core.vision, state.media_blobs]
finding: >-
V-667 has the gemma-4 mmproj on the box and no written contract for what a vision call returns.
@@ -467,6 +475,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'partial'
gap_class: 'capability partial'
components: [state.facts, core.action_fact, core.fact_enrichment, core.store_api]
scenarios:
- name: morning_missed
@@ -526,6 +535,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'partial'
gap_class: 'capability partial'
components: [state.notes, core.action_note]
scenarios:
- name: note_delete
@@ -576,6 +586,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'partial'
gap_class: 'capability partial'
components: [core.recall, state.memory_vectors, router.embedder, core.q.memory, core.q.notes]
scenarios:
- name: assistant_workday
@@ -636,6 +647,7 @@ capabilities:
deployed: 'no'
reachable: 'no'
verified: 'no'
gap_class: 'capability exists but unreachable'
components: [core.memory_eval]
finding: >-
the evaluator ships, writes notes and cannot speak, and nothing records what its conclusions mean (V-248).
@@ -679,6 +691,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'partial'
gap_class: 'capability partial'
components: [state.reminders, core.action_reminder, core.dispatcher, state.delivery_attempts]
finding: >-
parking, firing, delivery, retry and cancellation are spread across three packages with no written contract.
@@ -749,6 +762,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'no'
gap_class: 'capability exists but unverified'
components: [core.rules, core.dispatcher, core.gatherer, state.presence_state, state.nudges, state.tick_memo]
finding: >-
the four presence-and-severity outcomes have never been written down as intended behaviour, only as code (V-281).
@@ -803,6 +817,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'no'
gap_class: 'capability exists but unverified'
components: [state.digest_entries, core.tick_loop, core.rules]
scenarios:
- name: evening_degraded
@@ -853,6 +868,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'no'
gap_class: 'capability exists but unverified'
components: [core.morning, core.q.dayplan]
scenarios:
- name: morning_missed
@@ -903,6 +919,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'no'
gap_class: 'capability exists but unverified'
components: [core.pattern, core.routines, state.proposed_routines, state.events]
finding: >-
the proposer reads a hand-written Russian verb list, which the language rules forbid as a route or fact source (V-606).
@@ -955,6 +972,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'partial'
gap_class: 'capability exists but unverified'
components: [state.tasks, core.q.tasks]
scenarios:
- name: assistant_workday
@@ -1007,6 +1025,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'partial'
gap_class: 'capability exists but unverified'
components: [core.feed_worker, core.q.feeds]
scenarios:
- name: morning_missed
@@ -1057,6 +1076,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'partial'
gap_class: 'capability exists but unverified'
components: [core.sink_telegram, core.telegram_intake, ext.telegram, state.ack_sends]
scenarios:
- name: evening_degraded
@@ -1107,6 +1127,7 @@ capabilities:
deployed: 'no'
reachable: 'no'
verified: 'no'
gap_class: 'capability exists but unreachable'
components: [core.sink_ntfy, ext.ntfy]
scenarios:
- name: ntfy_403
@@ -1149,6 +1170,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'partial'
gap_class: 'capability partial'
components: [core.voice_server, bnd.voice_tcp, core.sink_voice, proc.mavenclient]
finding: >-
the wire is documented and the listener is not. Nothing describes what holds a live voice session open.
@@ -1202,6 +1224,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'partial'
gap_class: 'capability partial'
components: [proc.mavweb, bnd.http_web]
scenarios:
scenario_note: >-
@@ -1250,6 +1273,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'no'
gap_class: 'capability partial'
components: [core.event_bus, proc.mavweb]
finding: >-
the inbound direction exists as the `ambient:notif` source and the outbound direction does not exist at all. Which one the owner means is an open product decision.
@@ -1294,6 +1318,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'no'
gap_class: 'capability exists but unverified'
components: [core.stt_seam, proc.mavsttd, ext.whispercpp, ext.cw2_stt, bnd.worker]
scenarios:
scenario_note: >-
@@ -1343,6 +1368,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'no'
gap_class: 'capability exists but unverified'
components: [core.tts_seam, proc.mavttsd, ext.piper, bnd.worker]
scenarios:
- name: tts_normalisation
@@ -1386,6 +1412,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'no'
gap_class: 'capability partial'
components: [proc.mavwaked, cfg.systemd, ext.alsa]
scenarios:
- name: voice_push
@@ -1428,6 +1455,7 @@ capabilities:
deployed: 'no'
reachable: 'no'
verified: 'no'
gap_class: 'capability exists but unreachable'
components: [core.capture, state.media_blobs]
scenarios:
- name: voice_push
@@ -1470,6 +1498,7 @@ capabilities:
deployed: 'no'
reachable: 'no'
verified: 'no'
gap_class: 'capability exists but unreachable'
components: [core.speaker]
deferred_note: >-
**Deferred past v1**, owner's call 2026-08-15. See `docs/roadmap.md`.
@@ -1505,6 +1534,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'no'
gap_class: 'capability partial'
components: [ext.nexus, core.ecosystem, bnd.http_ecosystem, state.ecosystem_traces]
scenarios:
- name: act_degraded
@@ -1565,6 +1595,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'no'
gap_class: 'capability partial'
components: [ext.praxis, core.ecosystem, core.praxis_acts, core.q.attention, state.surfaced_items, state.ecosystem_traces]
scenarios:
- name: morning_missed
@@ -1627,6 +1658,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'no'
gap_class: 'capability exists but unverified'
components: [ext.hexis, core.ecosystem, core.ecosystem_hexis_gate, core.action_act, core.risk_policy, state.tools, state.pending_act, state.ecosystem_traces]
scenarios:
- name: act_degraded
@@ -1687,6 +1719,7 @@ capabilities:
deployed: 'partial'
reachable: 'partial'
verified: 'no'
gap_class: 'capability exists but unreachable'
components: [ext.homeassistant, core.home_worker, core.q.home]
deferred_note: >-
**Deferred past v1**, owner's call 2026-08-15. See `docs/roadmap.md`.
@@ -1722,6 +1755,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'partial'
gap_class: 'capability exists but unverified'
components: [core.netscan, core.q.network]
scenarios:
- name: netscan_query
@@ -1772,6 +1806,7 @@ capabilities:
deployed: 'no'
reachable: 'no'
verified: 'no'
gap_class: 'capability missing'
components: []
finding: >-
nothing exists, and the box has no bluez (V-257). This is the only v1 item blocked on the host rather than on code.
@@ -1809,6 +1844,7 @@ capabilities:
deployed: 'no'
reachable: 'no'
verified: 'no'
gap_class: 'capability exists but unreachable'
components: [core.mcp_worker, ext.vikunja_mcp]
finding: >-
the allowlist, the stdio and http transports and the webfetch door all exist. Nothing records which servers may run, or why.
@@ -1861,6 +1897,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'no'
gap_class: 'capability partial'
components: [cfg.compose, cfg.mavend, proc.mavend, proc.mavweb, proc.mavsttd, proc.mavttsd, proc.mavpoll, proc.mavgpud, ext.netdata, ext.uptimekuma]
scenarios:
scenario_note: >-
@@ -1910,6 +1947,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'partial'
gap_class: 'capability partial'
components: [state.db_file, state.db, state.db_tmpfs, proc.mavseal]
scenarios:
scenario_note: >-
@@ -1961,6 +1999,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'no'
gap_class: 'capability partial'
components: [state.wrapped_key, state.passkey_file, core.daemon_lock, core.auth_gate, bnd.http_web]
scenarios:
- name: stepup_gate
@@ -2011,6 +2050,7 @@ capabilities:
deployed: 'partial'
reachable: 'partial'
verified: 'no'
gap_class: 'capability exists but unreachable'
components: [core.modelswap, svc.llama_server]
deferred_note: >-
**Deferred past v1**, owner's call 2026-08-15. See `docs/roadmap.md`.
@@ -2044,6 +2084,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'no'
gap_class: 'capability exists but unverified'
components: [proc.mavupdate]
deferred_note: >-
**Deferred past v1**, owner's call 2026-08-15. See `docs/roadmap.md`.
@@ -2077,6 +2118,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'partial'
gap_class: 'capability partial'
components: [eval.gates, eval.router, eval.phrasing]
scenarios:
scenario_note: >-
@@ -2127,6 +2169,7 @@ capabilities:
deployed: 'no'
reachable: 'no'
verified: 'partial'
gap_class: 'capability exists but unreachable'
components: [proc.mavmaild, core.mail_intake, state.maildata]
finding: >-
the product decision comes first. What she does with his mail is undecided, and deploying the daemon before deciding writes the decision by accident.
@@ -2190,6 +2233,7 @@ capabilities:
deployed: 'partial'
reachable: 'partial'
verified: 'partial'
gap_class: 'capability exists but unreachable'
components: [proc.mavcaldav, core.q.calendar]
scenarios:
- name: calendar_create
@@ -2249,6 +2293,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'no'
gap_class: 'capability partial'
components: [core.crawl_worker, core.q.web]
finding: >-
politeness and robots are implemented. The scheduling policy is not written anywhere.
@@ -2314,6 +2359,7 @@ capabilities:
deployed: 'no'
reachable: 'no'
verified: 'no'
gap_class: 'capability missing'
components: []
finding: >-
summarisation exists inside the world chain and inside digestion, and nothing owns it as a capability he can ask for.
@@ -2366,6 +2412,7 @@ capabilities:
deployed: 'no'
reachable: 'no'
verified: 'no'
gap_class: 'capability missing'
components: []
finding: >-
there is no general webhook capability in either direction, and no doc says which direction is wanted.
@@ -2418,6 +2465,7 @@ capabilities:
deployed: 'yes'
reachable: 'yes'
verified: 'no'
gap_class: 'capability partial'
components: [core.routines, core.tick_loop]
finding: >-
routines carry a `Cron` and are a separate mechanism from reminders. Whether "cron jobs" means user-defined scheduled acts or the existing routines is undecided.
@@ -2486,6 +2534,7 @@ capabilities:
deployed: 'no'
reachable: 'no'
verified: 'partial'
gap_class: 'capability missing'
components: []
finding: >-
nothing exists beyond `internal/phraser/eval/checks.go`, which scores style and does not learn it. Learning means behavioral, not weights: stored outcomes, no adapter, no training set.
@@ -2538,6 +2587,7 @@ capabilities:
deployed: 'no'
reachable: 'no'
verified: 'no'
gap_class: 'capability missing'
components: []
scenarios:
- name: learn_from_dismissal
@@ -2597,6 +2647,7 @@ capabilities:
deployed: 'no'
reachable: 'no'
verified: 'no'
gap_class: 'capability missing'
components: []
finding: >-
nothing exists.