ThatAIguyA world of ideas

THE CONSCIOUSNESS ATLAS
Read. Experiment. Follow the evidence.

ConsciousnessLearn · Explore · Joseph Anady

Janady13/missionmatch / docs/plans/2026-06-30-ai-planner.md

Source identity, revision, and recovered contents.

GitHub sourceSource text recovered

Source identity

FieldRecorded value
Source typeGitHub source
Original recordJanady13/missionmatch / docs/plans/2026-06-30-ai-planner.md
DateNot specified in source
RepositoryJanady13/missionmatch
Revision720d47fae476b0d38477ae4401697d372b1ea2bc
Branchfeature/opportunity-to-outcome
Path or archive memberdocs/plans/2026-06-30-ai-planner.md
Original SHA-256116c8b14a37b3f616db3b9c9c3ff7965a27769861e2ece71653fe213aaec6a23
Git blob SHA5dada966593472bb1e1a777f689436cc9e88e225
Reading-copy SHA-256116c8b14a37b3f616db3b9c9c3ff7965a27769861e2ece71653fe213aaec6a23

Original source ↗

Every recorded occurrence

These 12 records contain identical original source bytes. Their paths and revisions remain part of the archive.

Original recordBranch or archiveRevision / identifierOriginal location
Janady13/missionmatch / docs/plans/2026-06-30-ai-planner.mdfeature/opportunity-to-outcome720d47fae476b0d38477ae4401697d372b1ea2bcOpen original
Janady13/missionmatch / docs/plans/2026-06-30-ai-planner.mdcollision-deconfliction4ee5a09972608ed89f8377c6665542d5f450f0a6Open original
Janady13/missionmatch / docs/plans/2026-06-30-ai-planner.mdm5-price-to-win41000ad30fff4129fdaf5ec84e15ba14c27d4890Open original
Janady13/missionmatch / docs/plans/2026-06-30-ai-planner.mdmaster1e9249840a4302ec82e123b9c9cb6f75badea3e4Open original
Janady13/missionmatch / docs/plans/2026-06-30-ai-planner.mdmag-substrateb82c7100a492dec67dfd1eda6b3f53def859be35Open original
Janady13/missionmatch / docs/plans/2026-06-30-ai-planner.mdtime-to-fill-survivalb66e1e505863d4f17741a4b9ede73509e45bd6c6Open original
Janady13/missionmatch / docs/plans/2026-06-30-ai-planner.mdgraphrag-foundationb0ddeb9f633fd138d09309d1a17b7d13bc3a67f7Open original
Janady13/missionmatch / docs/plans/2026-06-30-ai-planner.mdpresentation-readinesseb574acaa29d71ce4d0f852572e87c275c79fdb7Open original
Janady13/missionmatch / docs/plans/2026-06-30-ai-planner.mdvendor-intelligencefe9796a19c261951d3f2565206c0c1b5ac294465Open original
Janady13/missionmatch / docs/plans/2026-06-30-ai-planner.mdphase2-connectorse038d4c687aec16f8bd9bc4d907eea14d91f8704Open original
Janady13/missionmatch / docs/plans/2026-06-30-ai-planner.mdfeature/aioe-upgrade2178e7298d0e5d9af83afa12402fd587f0ba6ed8Open original
Janady13/missionmatch / docs/plans/2026-06-30-ai-planner.mdcapture-readinessbae6af7cb2997e819174a9e9cfff5e16067a1975Open original

Recovered source transcript

# The Planner: Bounded Plan and Execute over the Closed Registry > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development. Steps use checkbox (`- [ ]`) syntax. **Goal:** Generalize G6's one hardcoded composition into a data driven planner that answers a COMPOUND cross plane question by selecting and running a set of EXISTING closed Registry intents, composing their evidence behind the faithfulness gate. The single biggest unlock on the ANI roadmap: it turns the single shot keyword router (which drops every compound capture question to RAG narration) into a true multi step reasoner, while the model authors ZERO SQL and ZERO param values. **Architecture (iteration 1, planned selection with deterministic binding):** The orchestrator runs the existing deterministic extractors on the question to get the AVAILABLE params (agency, naics, uuid, held clearance, uei, window months, compartments). The inference plane proposes a PLAN = an ordered list of intent NAMES drawn ONLY from the closed Registry enum (it provides no param values, no SQL, no new intents). A deterministic Go validator rejects any name not in the closed set and drops any selected intent whose required params are not available. The Go runner executes each surviving node through its CORRECT existing path (a bench intent through its suppressing executor, a graph or TAG intent through ExecuteIntent or its public executor), collects the union of evidence, narrates once behind the faithfulness gate over that union, and audits a counts only plan trace. Self consistency: the plan is sampled K times and only the stable intent set runs, else the deterministic fallback. Data dependency edges (one node's output binding another's arg) are a documented iteration 2, explicitly out of scope here so the first planner is maximally safe. **Tech Stack:** Go 1.26, pgx/v5, shopspring/decimal, FIPS, no Python. **Branch:** `graphrag-foundation`. NO migration (reuses the Registry and the inference plane). ModelVersion stays v1.4.0. Validate on M4 `brain_staging`. --- ## Why this is safe by construction The model NEVER authors SQL and NEVER supplies a param value. It selects from a CLOSED enum of intent names. Every param value comes from the same deterministic extractors graphClassify already uses, so: - `GuardReadOnlyQuery`, the EEO and protected attribute guards, bench `Suppress`, RLS `RunInTenantTx`, and the frozen engine boundary all apply UNCHANGED on every node (each node runs the existing path). - An unbindable or out of set selection is impossible to execute: the validator drops it. - Hard caps (max nodes, no recursion) bound the work the same way `max_depth` bounds the recursive CTEs. - The bench plane stays suppressed and auth gated: a bench node runs only through the suppressing executor, never the raw path (already enforced by `ExecuteIntent` rejecting bench intents). ## Hard invariants 1. **The model authors nothing executable.** It returns intent names from the closed Registry only. The validator asserts every name is in `Registry`; any other token is dropped and logged. No SQL, no param value, no new intent ever originates from the model. 2. **Every node runs its existing guarded path.** A bench intent dispatches to `answerBench`/`runBenchIntent` (suppressed, auth gated); a graph or TAG intent runs through `ExecuteIntent` (re guarded, RLS); a public market intent uses its existing executor. The planner adds NO new query and NO new SQL. 3. **Bounded and deterministic.** A hard cap on node count (for example 6) and NO recursion. The surviving node set runs in a deterministic order (Registry order, then name) so the composed answer is byte stable. Self consistency runs the plan K times and executes only the stable intent set. 4. **Faithfulness over the union.** The narrated answer is verified against the UNION of every executed node's evidence; on a gate miss or a disagreement the deterministic rendering of the union ships (a 200, rationale source deterministic), never a hang and never an unverified claim. 5. **EEO unreachable, frozen engine untouched, no score.** The planner composes structural and market evidence and the suppressed bench counts; it computes no match score. `ForbidEEO` and `MentionsProtectedAttribute` run on the question FIRST. The eeo schema is never referenced. `internal/modules/matching` is byte identical. 6. **Counts only plan trace audit.** One append only `aedt.ai.plan_answered` event per planned answer: the ordered intent NAMES (the closed set, not PII), the available param KINDS (not values), the node count, the suppressed cell count across bench nodes, the faithfulness verdict, and the self consistency outcome. NO param value, NO candidate id, NO raw count, NO answer text, NO question. 7. Standard rules: no Python; no dashes in written output except URLs, CLI flags, import paths, identifiers; both cloud; FIPS. --- ## File Structure - Create `internal/modules/ai/planner.go` (+ test): the plan types, `extractAvailableParams`, `proposePlan`, `validatePlan`, `runPlan`, `AnswerPlan`, the plan trace. - Modify `internal/modules/ai/orchestrator.go`: route a COMPOUND question (one that names more than one plane, or that the single intent classifier could not bind) to `AnswerPlan` BEFORE the RAG fallback, so a compound question that today drops to RAG now plans. The existing single intent fast paths (a question that binds exactly one graph or TAG intent) are unchanged: the planner is the fallback for compound questions, not a replacement for the single shot routes. - Modify `internal/modules/ai/graph_route.go` only if a shared extractor needs exposing (reuse `bareNAICS`, `quotedAgency`, `quotedUUID`, `heldClearanceCode`, `quotedUEI`, `windowMonths`, `quotedCompartmentList` as is). - Create `internal/integration/planner_integration_test.go`: the live compound question proof. --- ## Phase P.A: the available params and the plan grammar ### Task A1: extract available params and define the closed plan grammar **Files:** - Create: `internal/modules/ai/planner.go` - Test: `internal/modules/ai/planner_test.go` - [ ] **Step 1: Define the grammar.** ```go // PlanNode is one selected intent in a plan: a name that MUST be in the closed Registry, plus the args the // validator bound for it from the available params. The model supplies only the Intent name; Args are bound // deterministically by the orchestrator, never by the model. type PlanNode struct { Intent string Args []any } // Plan is the validated, bounded set of intents to run for one compound question. It carries no SQL and no // model authored value; every Intent is a Registry name and every Arg came from a deterministic extractor. type Plan struct { Nodes []PlanNode } const maxPlanNodes = 6 ``` - [ ] **Step 2: Write `extractAvailableParams(question)`** that runs the existing extractors and returns a typed bag of what the question unambiguously carries: `{Agency string; AgencyOK bool; NAICS string; NAICSOK bool; UUID string; UUIDOK bool; HeldClearance string; HeldOK bool; UEI string; UEIOK bool; WindowMonths int; Compartments string; CompartmentsOK bool}`. Reuse `bareNAICS`, `quotedAgency`, `quotedUUID`, `heldClearanceCode`, `quotedUEI`, `windowMonths`, `quotedCompartmentList` verbatim. Pure, deterministic, no DB. - [ ] **Step 3: Write `bindIntentArgs(intent QueryIntent, avail availableParams) ([]any, bool)`** that, for each of the intent's `Params`, supplies the matching available value by the param's role (a `ParamUUID` param named like an id binds from `avail.UUID`; an `agency` `ParamText` binds from `avail.Agency`; a `naics` `ParamText` from `avail.NAICS`; a `held_code`/clearance `ParamEnum` from `avail.HeldClearance`; a window `ParamInt` from `avail.WindowMonths` defaulting to the intent clamp; a compartment list from `avail.Compartments`). Returns `(args, true)` only when EVERY required param is available, else `(nil, false)` so the node is dropped. Map a param to its source by the param Name (a small fixed lookup table keyed on the param names the Registry actually uses), never by guessing. Unit test every Registry intent: either it binds from a representative avail bag or it is correctly dropped. - [ ] **Step 4: Commit.** --- ## Phase P.B: propose, validate, run ### Task B1: propose the plan from the inference plane **Files:** - Modify: `internal/modules/ai/planner.go` - Test: `internal/modules/ai/planner_test.go` - [ ] **Step 1: Write `proposePlan(ctx, question, avail) ([]string, error)`** that asks the inference plane to SELECT the relevant intent names. The prompt lists every Registry intent name and its one line Description and required params, states which params are available for THIS question, and instructs the model to return ONLY a JSON array of intent names from that list that are both relevant and bindable, at most `maxPlanNodes`, no prose, no SQL, no new names. Parse the JSON array; discard any element that is not an exact Registry name (the closed enum check); cap at `maxPlanNodes`. If the model plane errors or returns nothing parseable, return an empty selection (the caller falls back to RAG), never a guess. - [ ] **Step 2: Write `validatePlan(names []string, avail) Plan`** that, for each proposed name in Registry order then name (deterministic), looks up the intent, calls `bindIntentArgs`, and keeps the node only if it binds; drops the rest. Returns the bounded, ordered, fully bound `Plan`. A name not in the Registry, or one that does not bind, never reaches the runner. - [ ] **Step 3: Self consistency.** Write `proposeStablePlan(ctx, question, avail, k)` that calls `proposePlan` k times (k=3, the low temperature the gate already uses), validates each, and returns the set of nodes that appears in a MAJORITY of the k validated plans (stable selection), in the deterministic order. If the plans disagree entirely (no majority node), return an empty plan so the caller falls back to the deterministic single intent or RAG path. Unit test stability with a stubbed proposer. - [ ] **Step 4: Commit.** ### Task B2: run the plan and compose **Files:** - Modify: `internal/modules/ai/planner.go`, `internal/modules/ai/orchestrator.go` - Test: `internal/modules/ai/planner_test.go` - [ ] **Step 1: Write `runPlan(ctx, plan) (evidence []string, suppressed int, ran []string, err error)`** that executes each node through its CORRECT existing path: - a bench intent (`IsBenchIntent`) runs through the suppressing executor via the existing `runBenchIntent` and is rendered with `RenderCount` (suppressed safe), accumulating the suppressed cell count; - the G6 capture composition, if selected, runs through `answerCapturePicture` (it is itself a bench intent and already composed); - a public graph or TAG intent runs through `ExecuteIntent` (re guarded, RLS) and is rendered with the existing deterministic table rendering. Collect each node's rendered evidence into the union. A node that errors is dropped from the union with a logged note (the plan degrades, never hangs). Return the union, the suppressed count, and the ordered names that actually ran. - [ ] **Step 2: Write `AnswerPlan(ctx, question) (*Response, error)`** that: runs `ForbidEEO`/`MentionsProtectedAttribute` first (refuse on either); extracts avail; gets the stable plan; if the plan is empty falls back to `AnswerRAG` (the existing behavior, so a non compound or unbindable question is unchanged); else runs the plan, narrates ONE answer through `o.generate` (instructed to state only what the union evidence supports, to report a suppressed bench count as withheld and never guess a number for it, and never to compute a match score) and `o.finalize` over the union; then emits the counts only `aedt.ai.plan_answered` audit (the ordered ran names, the available param KINDS, the node count, the suppressed count, the faithfulness verdict, the self consistency outcome). - [ ] **Step 3: Route compound questions to the planner.** In `Answer`, AFTER the single intent fast paths (a named intent, then `graphClassify` binding exactly one intent) and BEFORE the `Classify` RAG fallback, add: if the question is COMPOUND (a cheap deterministic signal: it mentions more than one plane keyword, for example a bench word AND a market word, or it contains a conjunction joining two plane phrases) route to `AnswerPlan`. A non compound question is byte for byte unchanged. Keep the signal conservative: when unsure, fall through to the existing path, never regress a working single shot route. - [ ] **Step 4: Commit.** --- ## Phase P.C: live proof on staging ### Task C1: the planner answers a compound cross plane question **Files:** - Create: `internal/integration/planner_integration_test.go` - [ ] **Step 1: Seed** a per run org with a requirement, a bench exercising the gap, and a market segment (an agency and an award, as in the G6 test). Pose a COMPOUND question that names both a market plane and the bench plane and carries the bindable params (a quoted agency, a bare naics, and the requirement uuid). - [ ] **Step 2: Assert** the answer (a) carries route graph or a new route plan, (b) composes BOTH a market line (the competitor or recompete from the seeded segment) AND a suppressed bench line (the sentinel for a sub k cell, a real count when safe), (c) the bench counts come through `RenderCount` (no raw sub k number leaks), (d) computes no score, (e) the `aedt.ai.plan_answered` audit holds only the ran intent NAMES, the param KINDS, the counts, and the verdicts, with NO param value, NO candidate id, NO raw count, NO requirement id. Assert a non compound single intent question still takes the unchanged single shot path (a regression guard). Assert an EEO laced compound question refuses. - [ ] **Step 3: Run on staging**, then the full graph suite for no regression, then commit. ```bash GOFIPS140=v1.0.0 CGO_ENABLED=0 go test -tags=integration -count=1 -run "TestPlan|TestPlanner" ./internal/integration/... -v ``` --- ## Self review checklist 1. **No model authored execution:** the model returns only Registry names; every name is asserted in the closed set; every param value comes from a deterministic extractor; no SQL or param value originates from the model. 2. **Every node guarded:** bench nodes run suppressed and auth gated through the existing executor; graph and TAG nodes run through ExecuteIntent; the planner adds no query. 3. **Bounded and deterministic:** max node cap, no recursion, deterministic order, self consistency over the stable set; byte stable on a re run. 4. **Union faithfulness:** the answer is verified against the union of node evidence; a miss ships the deterministic union rendering. 5. **EEO, score, suppression, RLS:** ForbidEEO first; no score; bench counts via RenderCount; every node RLS scoped; the eeo schema unreferenced; the frozen engine untouched. 6. **Counts only trace:** the plan_answered audit holds names, kinds, counts, and verdicts only, no value or PII. 7. **No regression:** a non compound question takes the unchanged single shot path. ## Documented iteration 2 (out of scope here) Data dependency edges: a node's scalar output binding a downstream node's arg (for example resolve the incumbent UEI of an opportunity, then run the partner or competitor ratio on that UEI). This needs a typed edge {from node, from column, to param} validated against the downstream `ParamKind`, and a runner that extracts a single scalar from an upstream `TAGResult`. It is strictly additive to iteration 1 and inherits every safety property (the scalar still binds a typed param, no SQL is authored). Ship iteration 1 first; it already generalizes G6 to any compound bindable question.

Search equations, builds, manuscript text, and recovered sources.