Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
789d715
feat: focus dashboard on collection workflow
wujinnuhuo Aug 3, 2026
4e4d872
feat: build collection control room interface
wujinnuhuo Aug 3, 2026
d718ea2
fix: bust cached control room stylesheet
wujinnuhuo Aug 3, 2026
fce2714
feat: implement canonical acquisition workbench design
wujinnuhuo Aug 3, 2026
635abbe
docs: define bounded discovery agent model
wujinnuhuo Aug 3, 2026
f5d69db
docs: specify discovery objective agent workspace
wujinnuhuo Aug 3, 2026
91d17c1
feat: add discovery objective workspace foundation
wujinnuhuo Aug 3, 2026
b5516e3
feat: govern discovery objective boundary revisions
wujinnuhuo Aug 3, 2026
539f778
feat: link discovery plans to bounded missions
wujinnuhuo Aug 3, 2026
e9bb51d
feat: add evidence-cited discovery assessments
wujinnuhuo Aug 3, 2026
3694c51
feat: scope agent runs to discovery objectives
wujinnuhuo Aug 3, 2026
6e010e2
feat: expose objective approval controls in workspace
wujinnuhuo Aug 3, 2026
6107df4
feat(discovery): add decision records and outcome feedback
wujinnuhuo Aug 3, 2026
18ff760
feat(agent): enforce objective boundary at execution
wujinnuhuo Aug 3, 2026
6415f8e
feat(workspace): show discovery loop artifacts
wujinnuhuo Aug 3, 2026
5d223a6
feat(discovery): bind agents and runs to plans
wujinnuhuo Aug 3, 2026
656663e
feat(workspace): surface evidence gaps and plan revisions
wujinnuhuo Aug 3, 2026
25b6328
feat(discovery): rank counterevidence explicitly
wujinnuhuo Aug 3, 2026
042a06f
feat(workspace): embed mission console operations
wujinnuhuo Aug 3, 2026
4f35dd1
fix(missions): reject stale plan execution
wujinnuhuo Aug 3, 2026
f54fbd3
fix(agent): scope idempotency to objectives
wujinnuhuo Aug 3, 2026
38fe074
style(migration): format agent boundary foreign keys
wujinnuhuo Aug 3, 2026
5e625f2
style(tests): format discovery objective fixture
wujinnuhuo Aug 3, 2026
536b70b
fix(discovery): bind agent evidence to source boundary
wujinnuhuo Aug 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions CONTEXT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# SourceOS

SourceOS is a personal operating system for turning traceable reality signals into product decisions. Its language separates evidence from claims and bounded agent action from operator authority.

## Agent Operation

**Discovery Agent**:
The bounded actor that plans and performs approved public-source collection, then returns traceable evidence, counterevidence, unknowns, and a proposed next action. It never makes product, commercial, or external-contact decisions.
_Avoid_: autonomous founder, full agent, chat assistant

**Operator Approval**:
The explicit decision by the operator that permits an action outside the Discovery Agent's approved source, tool, or budget boundary.
_Avoid_: confirmation, consent, automatic escalation

**Approved Collection Boundary**:
The versioned set of public sources, tools, request, time, and cost limits within which a Discovery Agent may act without a new Operator Approval.
_Avoid_: agent permission, unrestricted access

**Discovery Objective**:
The operator-owned, falsifiable question that gives a Discovery Agent a continuing reason to learn until its stop condition, pause, or budget limit is reached.
_Avoid_: project, research task, agent prompt

**Acquisition Plan**:
A versioned proposal from a Discovery Agent that states how one Discovery Objective should next be investigated, including sources, hypotheses, counterevidence targets, and bounded runs.
_Avoid_: mission, schedule, crawl configuration

**Plan Revision**:
A recorded change from one Acquisition Plan version to another that names the evidence or coverage gap responsible for the change. A revision may only use the current Approved Collection Boundary.
_Avoid_: retuning, silent optimization, agent learning

**Discovery Assessment**:
A versioned, evidence-cited Agent judgement about an Objective's support, counterevidence, unknowns, coverage gaps, and recommended next plan. It is not a business decision.
_Avoid_: answer, conclusion, validated result

**Need Hypothesis**:
An Agent-drafted, falsifiable explanation of a possible unmet need that awaits operator promotion to a Need Issue.
_Avoid_: discovered need, validated demand, product opportunity

**Blocked Assessment**:
A Discovery Assessment that states the Agent cannot produce a defensible next plan within the remaining evidence, boundary, and budget, and names the missing information or approval.
_Avoid_: failure, no result, keep researching

**Outcome Feedback**:
Observed tracking, delivery, retention, payment, refund, or support results from a product or service that the Discovery Agent may read to calibrate future discovery. It does not authorize the Agent to execute product or commercial actions.
_Avoid_: Agent action, market proof by itself

**Discovery Objective Workspace**:
The operator interface for one Discovery Objective, presenting its stop conditions, current Assessment, plan revisions, bounded runs, evidence, and approval decisions. It is not a chat-first interface.
_Avoid_: dashboard, task board, agent chat

**Discovery Decision Record**:
The closing record for a Discovery Objective, stating its decision state, cited support and counterevidence, resource use, unresolved unknowns, and later Outcome Feedback. It is the unit through which discovery quality is revisited.
_Avoid_: agent score, success metric, final answer

**Acquisition Mission**:
A concrete, approved collection instruction within one Acquisition Plan; it directs a bounded run and is not evidence or a demand claim.
_Avoid_: discovery objective, task, crawl job

**Evidence Candidate**:
Traceable collected material awaiting operator triage; its existence does not establish a Need Issue or product demand.
_Avoid_: validated insight, discovered need
11 changes: 11 additions & 0 deletions apps/api/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
acquisition_missions,
agent_runs,
delivery_records,
discovery_objectives,
experiments,
export,
external_signals,
Expand Down Expand Up @@ -90,6 +91,11 @@ async def lifespan(app: FastAPI):
app.include_router(export.router, prefix="/api/export", tags=["Export"])
app.include_router(need_issues.router, prefix="/api/need-issues", tags=["Need Issues"])
app.include_router(agent_runs.router, prefix="/api/agent-runs", tags=["Agent Runs"])
app.include_router(
agent_runs.objective_router,
prefix="/api/discovery-objectives",
tags=["Discovery Agent Runs"],
)
app.include_router(experiments.router, prefix="/api/experiments", tags=["Validation Experiments"])
app.include_router(product_theses.router, prefix="/api/product-theses", tags=["Product Theses"])
app.include_router(features.router, prefix="/api/features", tags=["Feature Definitions"])
Expand All @@ -100,6 +106,11 @@ async def lifespan(app: FastAPI):
feature_outcomes.router, prefix="/api/feature-outcomes", tags=["Feature Outcomes"]
)
app.include_router(today.router, prefix="/api/today", tags=["Today"])
app.include_router(
discovery_objectives.router,
prefix="/api/discovery-objectives",
tags=["Discovery Objectives"],
)
app.include_router(
ontology_hypotheses.router, prefix="/api/ontology-hypotheses", tags=["Ontology Hypotheses"]
)
Expand Down
26 changes: 26 additions & 0 deletions apps/api/routers/acquisition_mission_runs.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@
from packages.storage.models.acquisition_mission_run_signal import (
AcquisitionMissionRunSignal,
)
from packages.storage.models.acquisition_plan import AcquisitionPlan
from packages.storage.models.discovery_objective import (
ApprovedCollectionBoundary,
DiscoveryObjective,
)
from packages.storage.models.external_signal import ExternalSignal
from packages.storage.models.source import Source

Expand All @@ -57,6 +62,26 @@ async def _get_mission_or_404(db: AsyncSession, mission_id: uuid.UUID) -> Acquis
raise HTTPException(
status_code=422, detail="Acquisition Mission has no pinned source version"
)
if mission.acquisition_plan_id is not None:
plan = await db.get(AcquisitionPlan, mission.acquisition_plan_id)
if plan is None:
raise HTTPException(status_code=409, detail="Mission Plan is no longer available")
objective = await db.get(DiscoveryObjective, plan.objective_id)
current_boundary = await db.scalar(
select(ApprovedCollectionBoundary)
.where(ApprovedCollectionBoundary.objective_id == plan.objective_id)
.order_by(ApprovedCollectionBoundary.version.desc())
)
if (
objective is None
or objective.status != "active"
or current_boundary is None
or plan.boundary_id != current_boundary.id
):
raise HTTPException(
status_code=409,
detail="Plan is no longer permitted by the current approved boundary",
)
return mission


Expand Down Expand Up @@ -88,6 +113,7 @@ async def _persist_signal_drafts(
{
"id": uuid.uuid4(),
"mission_run_id": run.id,
"source_id": uuid.UUID(run.input_snapshot["source"]["id"]),
"lineage_key": draft.lineage_key,
"raw_artifact_key": draft.raw_artifact_key,
"source_label": draft.source_label,
Expand Down
28 changes: 28 additions & 0 deletions apps/api/routers/acquisition_missions.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
AcquisitionMissionResponse,
)
from packages.storage.models.acquisition_mission import AcquisitionMission
from packages.storage.models.acquisition_plan import AcquisitionPlan
from packages.storage.models.discovery_objective import (
ApprovedCollectionBoundary,
DiscoveryObjective,
)
from packages.storage.models.source_config_version import SourceConfigVersion

router = APIRouter()
Expand Down Expand Up @@ -55,6 +60,29 @@ async def create_acquisition_mission(
),
)

if body.acquisition_plan_id is not None:
plan = await db.scalar(
select(AcquisitionPlan).where(AcquisitionPlan.id == body.acquisition_plan_id)
)
if plan is None or str(body.source_id) not in plan.selected_source_ids:
raise HTTPException(
status_code=422,
detail="Mission source is not selected by the plan",
)
objective = await db.scalar(
select(DiscoveryObjective).where(DiscoveryObjective.id == plan.objective_id)
)
current_boundary = await db.scalar(
select(ApprovedCollectionBoundary)
.where(ApprovedCollectionBoundary.objective_id == plan.objective_id)
.order_by(ApprovedCollectionBoundary.version.desc())
)
if objective.status != "active" or plan.boundary_id != current_boundary.id:
raise HTTPException(
status_code=409,
detail="Plan is no longer permitted by the current approved boundary",
)

mission = AcquisitionMission(
**body.model_dump(),
source_config_version=config,
Expand Down
Loading
Loading