Skip to content

Roadmap — where the work has got to

Updated 2026-07-29.

This page carries status only. What each phase is, what it depends on and what "done" means all live in the delivery plan, which is a dated design record and deliberately does not track progress — a spec that changes every week stops being a record of what was decided.

One fact, one home: if a phase's meaning is wrong, fix the plan; if its status is wrong, fix this page.

Key

done
🔨 in flight
partially done, usable
not started
🚧 blocked — the blocker is named

Track 0 — groundwork

# Task Status Notes
0.1 Register the Discord application Intents enabled, installed to the test guild
0.2 Dedicated test guild
0.3 Benchmark corpus 59 questions in two sections — calibration (38) and questions (21). Both harnesses load only calibration, so 21 questions are never exercised. All cites: keys are empty; populating them is 2c.2. Entries now carry an expect axis naming the outcome the bot should reach, because only one of the four decline shapes should raise a ticket
0.4 Adversarial prompt-injection corpus 24 entries in test/corpus/adversarial.yaml
0.5 Moderation test corpus Blocks Phase 5 only
0.6 Public policy Provider named (Anthropic, Claude Haiku 4.5), what is and is not sent stated exactly, moderation marked not-yet-active
0.7 Enumerate corpus sources See corpus validation

Delivery phases

Phase Status Notes
1a-0 — Discord library spike disgo selected
1a — chat-platform + -discord Upstream, released
1b — Discord ingest Gateway reads allowlisted channels, survives forced disconnect with session resume
2 — knowledge index + ask Exit criteria met against the live group 2026-07-29. Rebuilt on v0.1.0 (2026-08-06): 53 of 103 sources qualify, 2,025 documents, 15,175 chunks — after an estate-wide documentation sweep added ~4,300 chunks and the internal-package exclusion removed 1,127
2b — provider benchmark Haiku 4.5 selected 2026-07-31decision record. £5/month at 50 questions a day. Provisional: citation accuracy (rubric #1) is unmeasured until 2c.2, and injection resistance is unscored
2c — retrieval spikes 2c.1's original result is withdrawn. "Limit 50 gained 2 code answers" came from a harness missing Config.Stateless, so all 72 calls shared one conversation and a question could be answered from an EARLIER question's passages (fixed in !25). Re-run clean on the v0.1.0 index: limit 8 → 50 converts nothing. The docs band is saturated at 20/20 at limit 8, so answered/declined can no longer discriminate at all. Three-model sub-question arbitration found the real signal — four questions answer INCOMPLETELY with the missing passages at ranks 10-24, which a boolean cannot see. Raising answer.DefaultLimit is blocked on #3
3 — Discord answering 🚧 Needs 2b and 0.6
4a — forge issue capability Delivered upstream 2026-08. forge v0.9.2 ships Issues (search, get, comments) and IssueFiler (create) as separate optional capabilities — split because read needs a read-only scope and write does not. forge-gitlab v0.6.4 implements both. Exit criteria verified here: a provider lacking them fails forge.As cleanly rather than panicking. Ships more than was asked for — Sanitise by default (R-ESC-9), an idempotency key for at-most-once filing, and search semantics where a FAILED duplicate search is never the same answer as "no duplicates" (R-ESC-3)
4b — GitLab escalation 🚧 Unblocked — 4a is released. Should follow #3: escalation turns a decline into a filed issue, and a composer that misfiles a refutation as a decline would file tickets for questions it can already answer
4c — gap explorer
5 — moderation 🚧 Needs 0.5
6 — feedback loop 🚧 Needs 3

What is actually next

2c.2 needs a human, and deliberately so. Expected citations cannot be derived from what the benchmark models cited: recall@k asks whether the right passage is in the top k, and ground truth taken from what a model cited when handed the top 8 is inside the top 8 by construction — recall would read ~100% however bad retrieval was, grading the retriever against its own output.

test/corpus/citation-shortlist.draft.yaml makes the authoring tractable: 25 ranked candidates per answerable question, to keep or replace. A question whose answer is not in the pool is the most valuable row in the file, being a recall failure the current metric cannot see.

2c.1's result is withdrawn, and the metric it used is exhausted. The original finding — deeper retrieval gaining two code answers — came from a harness that never set Config.Stateless, so every call carried every call before it and a question could be answered from an earlier question's passages. Re-run clean on the v0.1.0 index, limit 8 → 50 converts nothing, and the docs band answers 20 of 20 at limit 8. A boolean that is saturated cannot measure anything.

Sub-question decomposition can. Three independent models (gpt-5.5, gpt-5.6-sol, gpt-5.6-luna), each judging every question separately, agreed on 31 of 36 and found four questions answered INCOMPLETELY — with the missing passages at ranks 10, 14, 21 and 24. Limit 25 would close all four; limit 8 closes none. That is the reranker signal, and it was invisible to answered/declined.

Raising answer.DefaultLimit is nonetheless blocked on #3: at limit 50 the composer declined a question whose premise the passages refute, stating the correct answer inside the decline reason. Trading a completeness gain for a correctness loss is not an improvement, and the current metric would show neither.

4a is delivered. forge v0.9.2 and forge-gitlab v0.6.4 ship the issue capabilities, split into Issues and IssueFiler so a read-only deployment can decline the write path structurally rather than discovering the limit on its first attempt to file. Nothing is needed here to consume them.

4b should follow #3, not precede it. Escalation turns a decline into a filed GitLab issue. A composer that misfiles a refutation as a decline would file tickets asking for documentation that already exists and was already retrieved — the exact noise R-ESC-5's provenance labelling exists to keep out of the tracker.

Approved but unscheduled

Spec Why it is waiting
Published-site ingestion Approved 2026-07-29. Delivers the tutorial tier, which no source currently covers — the blog repository is private and stays that way. Sequencing against 2b and 2c is undecided (its Q-4)

Carried risks and chores

These are not phases and will not surface anywhere else.

Item Status
Rotate DISCORD_PHPBOTSCOUT_TOKEN — exposed in a debug log during 1a
Rotate GITLAB_TOKEN — surfaced by a test assertion during Phase 2
Least-privilege deployment token (R-OPS-29) — development uses a full-access PAT ⏳ Deployment phase
chat#4 — prompt caching ✅ Closed. chat v0.9.1 ships CachingChatClient + Config.CacheTTL. Not adopted: our stable prefix is ~513 tokens, below every provider's cacheable minimum, so it would cost a cache-write premium and return nothing. The lever is moderation, where one rubric is sent per message
chat-anthropic#1 — map-form schema silently mangled ✅ Closed. chat.Config.ResponseSchema is now typed *jsonschema.Schema, so the wrong shape is a compile error rather than silent mangling
Report the gtb generate defects upstream — three command-scaffold non-compliances, plus the docs generator leaking its preamble above the frontmatter and stamping AI author bylines
Release MR — cuts v0.1.0 when merged