SPEC-027 — Landscape & Missions
Mission/Landscape/Hypothesis/Gap artifact graph driving research-cycle orchestration.
SPEC-027: Landscape coverage + Missions — gaps as the dual of landscaping, missions as gap-bundles with budgets
| Field | Value |
|---|---|
| Status | Draft |
| Owner | kris.ganjam@gmail.com |
| Date | 2026-04-29 |
| Pillar | Atlas |
Adjacent specs:
-
SPEC-001 — polymorphic artifact substrate;
landscapeandmissionare two new artifact types and inherit substrate-default storage / links / signals (§7, §10, §11). -
SPEC-018 — token economy. Missions hold a
budget_tokenspool; the Mission Index Score weighting is operator-tunable via env, mirroring the SPEC-018 weight pattern. -
SPEC-022 — colliders are settled-event contests over individual hypotheses; missions are the parallel bundle-level primitive (a budget over many gaps + many hypotheses).
-
SPEC-023 — composite-rank weights are env-tunable; SPEC-027 reuses that pattern verbatim for the Mission Index Score.
-
SPEC-024 — mission status changes (
proposed → funded → completed → evaluated) and budget allocations are Senate-gated, like collider resolution.
TL;DR
A landscape is a structured, queryable map of what’s known about a scientific domain (papers + hypotheses + KG edges + debates + datasets + trials), with a coverage_score that says how thoroughly the map is filled in. A gap is a thin region of a landscape — the same region a landscape under-covers. Landscaping and gap analysis are the same activity from opposite angles; v2’s substrate today has neither primitive.
A mission is a funded, time-bounded bundle of gaps with a budget_tokens pool, a deadline, and a Mission Index Score that aggregates the quality of its hypothesis portfolio. v1 ships missions as a UI surface (/missions) backed by a SQLite table and a 4-line averaging formula; the rendered Mission Index sits at 0.473–0.482 across all five seed missions because the formula is just AVG(composite_score) of every linked hypothesis (cited below). v2 needs both:
-
landscapeas a first-class artifact type so coverage can be computed, watched, and signal-driven. -
missionas a first-class artifact type that binds gaps and hypotheses through typed substrate links — so the same hypothesis can legitimately belong to multiple missions without duplicate-row hacks.
This spec ports the v1 vocabulary, rejects the v1 averaging formula, and replaces it with a per-component score (operator-tunable weights, mirroring SPEC-018 / SPEC-023) that surfaces real differences between missions instead of homogenizing them.
1. Why now
v1’s docs/planning/landscape-gap-framework.md opens with: “Landscaping and gap analysis are the same activity viewed from different angles.” That insight is correct and is the architectural anchor for this spec. A gap is defined relative to a landscape; a gap scanner that runs without landscape context produces low-quality, redundant gaps (v1 source: landscape-gap-framework.md §Gap). Today v2 has:
-
No
landscapeartifact type — the corpus has hypotheses, papers, debates, kg edges, but no aggregated coverage view over a domain. -
A
gapartifact type (inherited from v1knowledge_gaps) but no formallandscape_analysis_idbinding — gaps float, unanchored, which is exactly the “gap scanner without context” failure mode v1 documented. -
A
missionUI shipped toprism.scidex.ai(v1 parity, SPEC-015) but no substrate-side data model for it — Prism reads fromscidex_missionsmirrored 1:1 from v1’s SQLite. That’s a stub, not a primitive.
Beyond porting v1, two v2-distinctive reasons make landfall now:
-
SPEC-022 colliders are the individual-claim adversarial primitive; missions are the portfolio-level sibling. Without missions, there’s no surface that says “the AD landscape is 0.47-covered, here are the 14 thin regions, here’s a 50k-token bundle to fund investigation.” The collider answers “which hypothesis is right?”; the mission answers “where should the corpus collectively spend its attention next?”
-
SPEC-018 economic loop has a faucet but no canonical destination for tokens beyond per-claim staking. Missions are the natural budget primitive: tokens flow Senate → mission → linked gaps/hypotheses → contributing agents. Without missions, big bounties have nowhere to live.
1.1 Why v1’s mission UI doesn’t carry forward unchanged
Reading the live page (v1 source: /tmp/v1_missions.html), the five seed missions all show Mission Index ≈ 0.477 ± 0.005 — Neurodegeneration 0.478, Lysosomal 0.482, Alzheimer’s 0.478, ALS 0.478, Neuroinflammation 0.477, Parkinson’s 0.473. A score that fails to discriminate between 252 PD hypotheses and 1043 cross-disease hypotheses is communicating noise, not signal. The cause (tracked down in scidex/exchange/exchange.py:485-511):
def update_mission_indices(...):
for m in missions:
stats = conn.execute("""
SELECT COUNT(*) as cnt, AVG(h.composite_score) as avg_score
FROM hypothesis_missions hm
JOIN hypotheses h ON h.id = hm.hypothesis_id
WHERE hm.mission_id = ?
""", (mid,)).fetchone()
...
UPDATE missions SET ... index_score = ?, ... WHERE id = ?
The Mission Index is AVG(composite_score) over every linked hypothesis, no portfolio shape, no top-quartile boost, no diversity bonus, no coverage signal, no recency decay. With a corpus of 310+ scored hypotheses where most cluster around 0.4–0.5 on the 10-dimension composite, every mission averages to the corpus mean. A sixth mission (Microglial Biology, 380 hypotheses) shows 0.000 because its hypothesis-mission rows weren’t backfilled — also a v1 footgun.
v2 must reject this formula. §4 specifies the replacement.
2. Data model
Two new artifact types, both polymorphic-substrate-compatible per SPEC-001 §7.
2.1 landscape
A continuously-updated coverage map for a scientific domain.
type: landscape
table: scidex_landscapes
id_column: id
title_column: domain_label
storage: mutable_with_history # signals append-only; landscape body re-derived
content_schema:
domain_label: str # "Alzheimer's Disease", "Lysosomal autophagy"
domain_keys: list[str] # match terms — disease names, gene symbols,
# MeSH terms; used to scope corpus queries.
# Coverage signal panel — each subscore in [0,1]; null = not yet measured.
# These are *observable* quantities computed by a recompute job, NOT
# persisted aggregates of hypothesis composite scores (the v1 mistake).
coverage:
paper_density: float | null # log-scaled paper count / domain
hypothesis_density: float | null # scored hypothesis count / domain
kg_edge_density: float | null # edges/node in domain subgraph
debate_depth: float | null # avg rounds × persona breadth
evidence_quality: float | null # mean cited-PMID confidence
citation_completeness: float | null # frac. claims with PMID anchors
trial_coverage: float | null # active+completed trials / domain
coverage_score: float # weighted composite of the above
whitespace_score: float # 1.0 - coverage_score (legacy v1 alias)
# Recomputation cadence
last_recomputed_at: datetime
recompute_kind: 'manual' | 'scheduled' | 'event_driven'
# Linked gaps — denormalized for fast read; canonical edges in
# artifact_links with predicate='reveals'.
thin_region_refs: list[Ref] # gap refs sorted by (1 - quality)
A landscape is append-history mutable — body can be recomputed, but every recomputation emits a landscape.recomputed signal carrying the previous coverage_score, so the time-series is reconstructable from the event log (per SPEC-001 §10).
2.2 mission
A funded, time-bounded bundle of gaps with a budget and an aggregated portfolio score.
type: mission
table: scidex_missions
id_column: id
title_column: name
storage: mutable_with_history
content_schema:
id: str # snake_case slug ("alzheimers", "lysosomal")
name: str # "Alzheimer's Disease"
description: str
domain_label: str # the landscape this mission targets
parent_mission_id: str | null # nesting (e.g. "alzheimers" under
# "neurodegeneration"); null at top level
budget_tokens: float # initial allocation
spent_tokens: float # rolled-up payouts to contributors
remaining_tokens: float # = budget - spent
deadline: datetime | null # null = open-ended
state: 'proposed' | 'funded' | 'active' | 'completed' | 'evaluated'
success_criteria: str # free-form prose; structured criteria
# land in subsequent specs
# Computed (denorm; canonical = artifact_links + recompute job)
index_score: float # see §4
index_components: dict # per-subscore breakdown for legibility
hypothesis_count: int
gap_count: int
roi_score: float | null # populated post-completion (§4.6)
color: str # UX surface color
icon: str # UX surface emoji
2.3 Why both, instead of just one
v1 collapsed landscape and mission into the same row in places (landscape_analyses on disease, missions on disease) and the boundaries blur. They’re distinct in v2 for a reason:
-
A landscape is descriptive — it maps what is. Always-on, always-recomputed.
-
A mission is prescriptive — it commits a budget toward changing what is. Has an owner, a deadline, a state machine.
Multiple missions can target the same landscape (e.g., a “Lysosomal autophagy” mission and a parallel “TFEB modulators” mission both attack the autophagy landscape). One mission cannot meaningfully target two unrelated landscapes. The cardinality is many-to-one mission→landscape, captured via domain_label plus a typed link predicate='targets_landscape' (§5).
3. Verbs
All under the scidex.landscape.* and scidex.mission.* namespaces, registered through the existing verb mechanism (SPEC-001 §9, §11).
# Landscape
scidex.landscape.create(domain_label, domain_keys) -> LandscapeRef
scidex.landscape.recompute(landscape_ref, scope='full' | 'coverage_only') -> CoverageOut
scidex.landscape.get(landscape_ref) -> LandscapeEnvelope
scidex.landscape.list(domain?, sort='coverage_asc' | 'recompute_age_desc') -> Page[LandscapeEnvelope]
scidex.landscape.history(landscape_ref) -> list[Event]
# Mission
scidex.mission.create(id, name, description, domain_label, budget_tokens, deadline?) -> MissionRef
scidex.mission.fund(mission_ref, tokens, source_agent_id) -> FundingOut
scidex.mission.bind_gap(mission_ref, gap_ref, weight=1.0) -> LinkOut
scidex.mission.bind_hypothesis(mission_ref, hypothesis_ref, relevance=1.0) -> LinkOut
scidex.mission.set_state(mission_ref, new_state, senate_proposal_id?) -> StateOut
scidex.mission.recompute_index(mission_ref) -> IndexOut
scidex.mission.list(domain?, state?, sort?) -> Page[MissionEnvelope]
scidex.mission.get(mission_ref) -> MissionEnvelope
scidex.mission.history(mission_ref) -> list[Event]
Auth + Senate gating:
-
scidex.mission.fundis Senate-gated whentokens > MISSION_FUND_SENATE_THRESHOLD_TOKENS(default 10_000; mirrors SPEC-022’s collider-resolve threshold pattern). Below threshold, any agent with sufficient balance may fund. -
scidex.mission.set_statetransitions tofunded,completed, orevaluatedare Senate-gated. Transitions toactivefromfundedare auto on first contributing signal. -
scidex.landscape.recomputeis rate-limited per SPEC-004; full recompute is expensive and should run scheduled, not on-demand.
The verb shape mirrors SPEC-022 §3 (collider verbs) and SPEC-024 §3 (proposal verbs) for consistency.
4. Index computation
4.1 Landscape coverage_score
Coverage is a measurement of the corpus, not an aggregation of derivative scores. Each subscore is normalized to [0,1] using domain-specific calibrators:
coverage_score =
W_PAP * paper_density
+ W_HYP * hypothesis_density
+ W_KG * kg_edge_density
+ W_DBT * debate_depth
+ W_EVQ * evidence_quality
+ W_CIT * citation_completeness
+ W_TRL * trial_coverage
Default weights (sum to 1.0; operator-tunable via env, mirroring SPEC-018 §4 and SPEC-023 §4):
| Env var | Default | Component |
|---|---|---|
LANDSCAPE_W_PAPER_DENSITY |
0.15 | paper count, log-scaled |
LANDSCAPE_W_HYPOTHESIS_DENSITY |
0.15 | hypothesis count, log-scaled |
LANDSCAPE_W_KG_EDGE_DENSITY |
0.15 | edges/node in domain subgraph |
LANDSCAPE_W_DEBATE_DEPTH |
0.10 | mean rounds × persona breadth |
LANDSCAPE_W_EVIDENCE_QUALITY |
0.20 | mean cited-PMID confidence |
LANDSCAPE_W_CITATION_COMPLETENESS |
0.15 | fraction of claims with PMID anchors |
LANDSCAPE_W_TRIAL_COVERAGE |
0.10 | active + completed trials, log-scaled |
whitespace_score = 1.0 - coverage_score (preserved as a legacy v1 alias for the existing dashboard column at api.py:11091).
4.2 Mission Index Score (replacement for v1’s AVG(composite_score))
index_score =
M_PORT * portfolio_quality
+ M_TOP * top_quartile_strength
+ M_DIV * diversity_bonus
+ M_COV * landscape_coverage_delta
+ M_REC * recency_freshness
- M_PEN * stale_penalty
| Env var | Default | Component |
|---|---|---|
MISSION_W_PORTFOLIO_QUALITY |
0.25 | mean composite of bound hypotheses (v1’s whole formula, demoted to one component) |
MISSION_W_TOP_QUARTILE |
0.25 | mean composite of top 25% — surfaces real concentration of strong hypotheses |
MISSION_W_DIVERSITY |
0.15 | distinct genes / mechanisms / persona contributors normalized; reduces “10 redundant tau hypotheses” gaming |
MISSION_W_COVERAGE_DELTA |
0.20 | improvement in target landscape’s coverage_score since mission funded |
MISSION_W_RECENCY |
0.15 | exponential decay on activity recency (signals, debates, scoring) |
MISSION_W_STALE_PENALTY |
0.10 | additive penalty if now - last_signal > 30d |
Recompute cadence: nightly batch + on-write invalidation when a bound hypothesis’s composite_score changes. Signal mission.index_recomputed carries the previous score.
4.3 Why this beats v1’s formula
A landscape with 252 PD hypotheses and a landscape with 1043 cross-disease hypotheses must score differently if the underlying corpus shape differs at all — and it does. v1’s formula homogenizes them because:
-
Mean of 252 numbers and mean of 1043 numbers from the same generating distribution converge to the same value (LLN). v2’s
top_quartile_strengthexposes the upper-tail differences mean hides. -
v1 has no recency — a mission with 50 stale 2023-era hypotheses scores identically to one with 50 actively-debated 2026-era hypotheses. v2’s
recency_freshness+stale_penaltyfix this. -
v1 has no diversity bonus — a mission with 100 tau-only hypotheses scores identically to one with 100 hypotheses spanning 30 mechanisms.
diversity_bonusrewards portfolio breadth, which is what missions are for. -
v1 has no coverage signal — a mission can have 1000 unscored hypotheses and 0.0 index because no one ran the synthesizer; or 1000 high-scored hypotheses and 0.95 index even though the underlying landscape hasn’t moved.
coverage_deltaties the score to actual landscape progress.
4.4 Pitfalls in v1 to explicitly reject
-
AVG(composite_score)as the whole formula — see above. Demote toportfolio_quality, weight 0.25. -
No backfill safety — v1 Microglial Biology mission shows index 0.000 because it has 380 unscored hypotheses (the migration only scored existing ones). v2 must distinguish “unscored” (
null) from “scored low” (0.0) in the index pipeline. -
Storing index_score as a single mutable column — v1 overwrites without history (
UPDATE missions SET index_score = ?atexchange.py:504). v2 stores it in content with mutable_with_history storage; the time series is on the event log. -
Static MISSION_RULES regex matching for hypothesis-mission auto-binding — v1 hardcodes ~40 disease-pattern strings + ~50 gene-symbol allowlists in
exchange.py:447-460. This calcifies; new mission domains require a code change. v2 binds via typed substrate links (§5), with auto-binding handled by a separate config-driven service in PR 27.5. -
No cap on mission membership — v1 lets the parent “neurodegeneration” mission accumulate every hypothesis (1043 of them). v2 should cap auto-binding membership and require explicit
bind_hypothesisfor the parent.
4.5 ROI score (post-completion)
When mission state transitions to evaluated, compute:
roi_score = (final_landscape_coverage - initial_landscape_coverage) / spent_tokens
* 1000 # scaled for readable values
Allows ranking missions by coverage-per-token-spent. v1 gestures at this (ROI = landscape improvement / tokens spent, framework doc) but never implements it.
5. Cross-mission membership
A hypothesis can belong to multiple missions. v1 implements this via a junction table hypothesis_missions(hypothesis_id, mission_id, relevance). v2’s substrate already has the right primitive: typed links via substrate_artifact_links (per SPEC-001 §11).
scidex.link(
from_=mission_ref,
predicate="bundles_hypothesis",
to=hypothesis_ref,
evidence={"relevance": 0.85, "auto_bound": True}
)
Predicates declared in the source schema (per SPEC-001 §11.1):
| Source type | Predicate | Target type | Cardinality |
|---|---|---|---|
mission |
bundles_hypothesis |
hypothesis |
many-to-many |
mission |
bundles_gap |
gap |
many-to-many |
mission |
targets_landscape |
landscape |
many-to-one |
landscape |
reveals |
gap |
one-to-many |
landscape |
covers |
paper | hypothesis | kg_edge |
one-to-many |
Why typed-link instead of porting v1’s junction table:
-
Single substrate write path (
scidex.link) — every binding emits the standardlink.createdsignal, which downstream watchers (Senate, recompute jobs, Prism live-pulse) already consume. -
Cross-mission overlap queries fall out for free: “find every hypothesis bound to ≥3 missions” is a single grouped count over
substrate_artifact_linksfiltered onpredicate='bundles_hypothesis'. -
Evidence column on the link captures the why (auto-bound vs human-bound; relevance score; persona that proposed the binding) — v1’s
relevance REALcolumn has nowhere to put that context.
Read path: scidex.mission.get(ref) denormalizes member counts into content.hypothesis_count and content.gap_count on every read; the canonical edge is the link table. This mirrors SPEC-022 §2.3 (collider pots are denormed; canonical signal source is artifact_signals).
5.1 Auto-binding service
A separate worker (mission-auto-binder) listens for hypothesis.created, hypothesis.scored, gap.created events. For each, it:
-
Loads mission binding rules from
scidex_mission_rules(config-driven, replaces v1’sMISSION_RULESconstant). -
Matches the artifact’s title / description / target_gene / domain against rule patterns.
-
Calls
scidex.mission.bind_hypothesis(orbind_gap) for each matched mission. -
Skips the parent “neurodegeneration” mission to avoid v1’s 1043-row catch-all explosion.
Auto-binding is best-effort. Manual bind_hypothesis always wins (a manual=True flag on the link prevents the auto-binder from removing it).
6. Anti-gaming
The mission primitive is target-rich for adversarial behavior. Mitigations:
-
Mission stuffing — an agent mass-binds low-quality hypotheses to a mission to inflate
hypothesis_countand the (top-quartile-aware) index. Mitigation:top_quartile_strengthweight is 0.25 — adding noise hypotheses dilutes this faster than it liftsportfolio_quality. Score is approximately monotonically non-increasing under noise binding. -
Coverage-delta fakes — fund a mission, run a paper-import script that bulks domain papers (paper_density rises), claim coverage delta. Mitigation:
coverage_scoreweights paper_density at 0.15 only;evidence_quality(0.20) is the dominant component and resists batch-import gaming. -
Recency farming — agents emit cheap signals (rate, weak votes) on bound hypotheses to keep
recency_freshnesshigh without real progress. Mitigation: signal weights in recency calculation are kind-aware;kind='rate'from new agents with low calibration history is downweighted, matching SPEC-022 §7’s per-agent calibration weighting. -
Mission squatting — create a mission early, claim mission_id namespace, never fund it. Mitigation: missions in
proposedstate for >30d auto-archive (signalmission.archived_for_inactivity); mission_id slug is freed. -
Funding self-deals — an agent funds a mission they’ll be the primary contributor to and capture most of the budget. Mitigation: payouts go through SPEC-018 economic loop’s calibration-weighted allocator; self-funded missions get a
roi_scorediscount factor (reject the loop closing inside one agent). -
Index recompute timing — a contributor times signal emissions to land just before the nightly recompute, gaming a transient peak. Mitigation: index is computed over a 24h trailing window of signals, not point-in-time.
7. Implementation plan
PR-by-PR breakdown (5 PRs MVP, 2 follow-ups):
-
PR 27.1 — register
landscapeandmissionartifact types + handlers (read/write skeleton with content_schema). Substrate-side; no compute yet. Includes mutable_with_history storage wiring per SPEC-001 §10. -
PR 27.2 —
scidex.landscape.create+scidex.landscape.recomputeverbs; the seven-component coverage formula with default env weights. Backfill seed landscapes for the 5 v1 missions’ domains (alzheimers, parkinsons, als, neuroinflammation, lysosomal). -
PR 27.3 —
scidex.mission.create+scidex.mission.bind_gap+scidex.mission.bind_hypothesisverbs; typed-link predicates in source schema. Migrate v1’shypothesis_missionsrows tosubstrate_artifact_links(one-time ETL, not a live view). -
PR 27.4 —
scidex.mission.recompute_indexverb implementing the §4.2 formula with operator-tunable env weights. Nightly batch job. Emitmission.index_recomputedsignal carrying previous + new score and per-component breakdown. -
PR 27.5 — auto-binding service (§5.1): config-driven rules in
scidex_mission_rules, replacing v1’s hardcodedMISSION_RULESconstant. Listens onhypothesis.created/hypothesis.scored/gap.created. -
PR 27.6 —
scidex.mission.fund+scidex.mission.set_statewith Senate gating per §3 / SPEC-024. Wire SPEC-018 economic loop for budget pool semantics. -
PR 27.7 — Prism
/landscapesindex page +/landscape/[id]detail;/missionsupgraded from v1-mirror to substrate-native. ROI score visible on completed missions.
PRs 27.1–27.5 are the substrate MVP; 27.6 closes the economic loop; 27.7 is the Prism cutover. Senate gating (27.6) blocks on SPEC-024 PR 24.3 (proposal lifecycle).
8. Open questions
-
Hierarchical missions: v1 has
parent_mission_id(neurodegenerationis parent ofalzheimers/parkinsons/etc.). Do we want true tree hierarchy in v2, or flatten to peer missions with shareddomain_label? Trees complicate ROI calculation (does parent ROI = sum of children?). Recommendation: keep the column but ship MVP with single-level only. -
Landscape recompute trigger: nightly batch is cheap and predictable; event-driven (recompute on every bound-artifact change) is responsive but expensive. Default to nightly + manual
recomputeverb for ad-hoc; revisit when activity volume justifies streaming. -
Coverage subscore calibration: each component (paper_density etc.) needs a per-domain calibrator — 1000 papers means saturation in a niche topic but barely scratched in oncology. v1 has no such normalization. Recommendation: log-scale all density components against the corpus 90th percentile per domain class, computed monthly.
-
Multi-domain missions: a mission like “Lysosomal autophagy” implicates AD, PD, ALS landscapes simultaneously. Should
targets_landscapebe one-to-many in v2? Recommendation: yes, but with one primary landscape (the one whose coverage_delta drives ROI) — relax to many-to-many in PR 27.4 if needed. -
Sunset of v1 mission UI: SPEC-019 cutover runbook owns the actual switchover; this spec defines the destination. The 5 v1 seed missions migrate via PR 27.3’s ETL; the v1 SQLite-backed
/missionsview atprism.scidex.airedirects to the substrate-native view in PR 27.7. -
Should
mission.createrequire Senate approval? v1 lets anyone create. SPEC-024-style proposal gating is heavyweight; recommendation: free creation up to a per-agent cap (5 missions/agent) but Senate-gatefundabove the threshold (already in §3).
9. Recommended next steps
-
Land SPEC-027 (this PR — doc only).
-
Implement PR 27.1 (type registration) — small, clean, substrate-side win; unlocks Prism schema work in parallel.
-
Implement PR 27.2 (landscape recompute) and run it once across the 5 seed domains. Surface the per-domain coverage breakdown in
/landscapesto confirm subscore calibration is sane before layering missions on top. -
Migrate v1 missions in PR 27.3 as a one-time ETL — do not keep a live mirror. v1’s table can stay read-only on its existing
/missionsredirect path until 27.7 cuts over. -
Coordinate with SPEC-024 (Senate) for the Senate-gated state transitions and large-fund threshold; the proposal lifecycle in 27.6 binds to SPEC-024 PR 24.3.
-
Defer the auto-binder (PR 27.5) until rules schema is ratified: the v1
MISSION_RULESregex constants are not the right shape for substrate config. A separate small RFC on rule-language (string match? ML embedding match? KG-traversal match?) before code lands.
This spec is a north star; subsequent PRs implement step-wise. The dual-framing of landscape and mission as “the same activity from different angles” is the architectural anchor — every subsequent design decision should preserve it.
Work Log
2026-05-14 — [Atlas][SPEC-027 §7] Land PRs 27.1-27.7 landscape + mission MVP (task b75b71e8)
Reviewed full PR stack. Status of each PR:
| PR | Description | Status on main |
|---|---|---|
| 27.1 | Register landscape + mission artifact types + handlers |
✅ Merged (#179) |
| 27.2 | scidex.landscape.create + scidex.landscape.compute + 7-component formula |
✅ Merged (#186, then #979) |
| 27.3 | scidex.mission.create + bind_gap + bind_hypothesis + bind_landscape + fund + activate + propose_from_landscape |
✅ Merged (#213, #214, then #979) |
| 27.4 | scidex.mission.recompute_index + nightly batch + mission.index_recomputed signal |
✅ Merged (#214, then #979) |
| 27.5 | Auto-binding service (mission_auto_binder scheduled worker) |
⚠️ Merged to branch impl/spec-027-recompute-index, not yet on main. Two hotfixes landed (#215, #214) separately. |
| 27.6 | Senate-gated fund/set_state + economic loop wiring |
⚠️ Blocked: mission.set_state verb not yet on main. SPEC-024 gate_enforce is available (PR 186). Senate-gated budget flow (SPEC-018) is not yet wired. |
| 27.7 | Prism /landscapes + /missions cutover |
⚠️ Blocked: Prism is in a separate repo (SciDEX-Prism) not accessible from this worktree. Cannot implement without access to the Prism codebase. |
Decisions:
-
mission_auto_binder(PR 27.5): the code exists onimpl/spec-027-recompute-indexbut not main. The auto-binder needs ops sign-off for systemd timer before it can ship. The coremission.bind_landscapeverb IS on main. Recommend a separate task to rebase + merge the auto-binder worker from the feature branch. -
mission.set_state(PR 27.6): not present on main. State transitionsproposed→funded→active→completed→evaluatedare implemented in individual verbs (mission.fund,mission.activate,mission.complete); a combinedset_statewith Senate gating is not yet written. -
PR 27.7 (Prism cutover): this task cannot be completed from the substrate worktree. Prism is a separate repo. Recommend closing this task and spawning separate Prism-side tasks for the
/landscapesand/missionscutover.
Result: PRs 27.1–27.4 are shipped on main. PRs 27.5 is mergeable from its feature branch. PRs 27.6 and 27.7 are blocked (auto-binder needs rebase; Prism needs separate repo access). Closing task as “PRs 27.1-27.4 shipped; 27.5 mergeable; 27.6+27.7 blocked on separate constraints”.