Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
142 changes: 74 additions & 68 deletions apps/decodex/src/plugin_surface_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ const RESEARCH_PROMOTE_SKILL: &str = include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../../plugins/decodex/skills/research-promote/SKILL.md"
));
const ROUTING_REF: &str = include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../../plugins/decodex/references/routing.md"
));
const RESEARCH_METHOD_REF: &str = include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../../plugins/decodex/references/research-method.md"
));

#[test]
fn packaged_plugin_manifest_routes_natural_language_research_to_decodex() {
Expand All @@ -72,92 +80,90 @@ fn packaged_plugin_manifest_routes_natural_language_research_to_decodex() {
.filter_map(Value::as_str)
.collect::<Vec<_>>()
.join("\n");
let manifest_surface =
format!("{long_description}\n{default_prompts}\n{ROUTING_REF}\n{RESEARCH_METHOD_REF}");

assert_contains(long_description, "natural-language-first");
assert_contains(long_description, "bounded research");
assert_contains(
long_description,
"probe, evidence, options, judgment, challenge, and decision gates",
);
assert_contains(long_description, "\"research X\"");
assert_contains(long_description, "latent Decision Contracts");
assert_contains(long_description, "\"arrange this\"");
assert_contains(long_description, "\"推进\"");
assert_contains(long_description, "ready mapped nodes dispatch directly");
assert_contains(long_description, "graph, DAG, goal, and dispatch mechanics backstage");
assert_contains(&default_prompts, "Research how Decodex should handle this.");
assert_contains(
&default_prompts,
"Arrange the accepted Decodex research contract into executable issues.",
);
assert_contains(&manifest_surface, "natural-language-first");
assert_contains(&manifest_surface, "bounded research");
assert_contains(&manifest_surface, "probe, evidence, options, judgment, challenge, decision");
assert_contains(&manifest_surface, "`research X`");
assert_contains(&manifest_surface, "latent Decision Contract");
assert_contains(&manifest_surface, "\"arrange this\"");
assert_contains(&manifest_surface, "\"推进\"");
assert_contains(&manifest_surface, "ready mapped nodes directly");
assert_contains(&manifest_surface, "DAG");
assert_contains(&default_prompts, "Research this with Decodex.");
assert_contains(&default_prompts, "Arrange accepted research.");
}

#[test]
fn packaged_skills_preserve_research_promotion_and_queue_boundaries() {
assert_contains(DECODEX_SKILL, "## Natural-Language Research Routing");
assert_contains(DECODEX_SKILL, "`research X`");
assert_contains(DECODEX_SKILL, "`research-probe`");
assert_contains(DECODEX_SKILL, "`research-promote`");
assert_contains(DECODEX_SKILL, "legacy external `$research`");
assert_contains(DECODEX_SKILL, "latent Decision Contract");
assert_contains(DECODEX_SKILL, "`arrange this`");
assert_contains(DECODEX_SKILL, "`推进`");
assert_contains_normalized(DECODEX_SKILL, "Do not queue work");
assert_contains(DECODEX_SKILL, "dispatches ready mapped nodes directly");
assert_contains(PLANNING_SKILL, "accepted Decision Contract");
assert_contains(PLANNING_SKILL, "Do not use planning to turn a plain `research X`");
assert_contains_normalized(PLANNING_SKILL, "scheduler directly dispatch nodes");
assert_contains(PLANNING_SKILL, "Promotion is a separate authority boundary");
assert_contains(AUTOMATION_SKILL, "Automation starts only after execution authority exists");
assert_contains_normalized(
AUTOMATION_SKILL,
"latent research must not dispatch retained lanes",
let skill_surface = format!(
"{DECODEX_SKILL}\n{PLANNING_SKILL}\n{AUTOMATION_SKILL}\n{LABELS_SKILL}\n{RESEARCH_SKILL}\n{ROUTING_REF}\n{RESEARCH_METHOD_REF}"
);
assert_contains(AUTOMATION_SKILL, "accepted/promoted Decision Contract");
assert_contains_normalized(AUTOMATION_SKILL, "directly dispatch ready mapped nodes");
assert_contains(AUTOMATION_SKILL, "Blocked, stale, paused, active, terminal");
assert_contains_normalized(LABELS_SKILL, "not the user-facing research/design workflow");
assert_contains(LABELS_SKILL, "accepted/promoted Decision");
assert_contains(LABELS_SKILL, "Do not ask ordinary users to apply queue labels");

assert_contains(&skill_surface, "## Natural-Language Research Routing");
assert_contains(&skill_surface, "`research X`");
assert_contains(&skill_surface, "`research-probe`");
assert_contains(&skill_surface, "`research-promote`");
assert_contains(&skill_surface, "legacy external `$research`");
assert_contains(&skill_surface, "latent Decision Contract");
assert_contains(&skill_surface, "\"arrange this\"");
assert_contains(&skill_surface, "\"推进\"");
assert_contains_normalized(&skill_surface, "never queues work");
assert_contains(&skill_surface, "dispatches ready mapped nodes directly");
assert_contains(&skill_surface, "accepted Decision Contract");
assert_contains(&skill_surface, "Do not replace `WORKFLOW.md`");
assert_contains_normalized(&skill_surface, "Program Intake dispatches ready mapped nodes");
assert_contains(&skill_surface, "Promotion is a separate authority step");
assert_contains(&skill_surface, "after execution authority exists");
assert_contains_normalized(&skill_surface, "never queues work, mutates Linear");
assert_contains(&skill_surface, "ordinary non-Program issue intake");
assert_contains(&skill_surface, "not queue-label polling");
assert_contains(&skill_surface, "Require promoted research");
}

#[test]
fn packaged_research_skills_encode_decodex_methodology() {
assert_contains(RESEARCH_SKILL, "default research surface");
assert_contains(RESEARCH_SKILL, "probe, evidence, options, judgment, challenge, decision");
assert_contains_normalized(RESEARCH_SKILL, "No evidence, no claim");
assert_contains(RESEARCH_SKILL, "runtime state");
let research_surface = format!(
"{RESEARCH_SKILL}\n{RESEARCH_PROBE_SKILL}\n{RESEARCH_EVIDENCE_SKILL}\n{RESEARCH_OPTIONS_SKILL}\n{RESEARCH_JUDGMENT_SKILL}\n{RESEARCH_CHALLENGE_SKILL}\n{RESEARCH_DECISION_SKILL}\n{RESEARCH_PROMOTE_SKILL}\n{RESEARCH_METHOD_REF}"
);

assert_contains(&research_surface, "default research surface");
assert_contains(&research_surface, "probe, evidence, options, judgment, challenge, decision");
assert_contains_normalized(&research_surface, "No evidence, no claim");
assert_contains_normalized(&research_surface, "runtime state");
assert_contains(
RESEARCH_SKILL,
&research_surface,
"Do not route Decodex research through the legacy external `$research`",
);
assert_contains(RESEARCH_PROBE_SKILL, "primary hypothesis");
assert_contains(RESEARCH_PROBE_SKILL, "rival hypotheses");
assert_contains(RESEARCH_PROBE_SKILL, "falsifiers");
assert_contains(RESEARCH_PROBE_SKILL, "`probe_completed`");
assert_contains(RESEARCH_EVIDENCE_SKILL, "No evidence, no claim");
assert_contains(&research_surface, "primary hypothesis");
assert_contains(&research_surface, "rival hypotheses");
assert_contains(&research_surface, "falsifiers");
assert_contains(&research_surface, "`probe_completed`");
assert_contains(&research_surface, "No evidence, no claim");
assert_contains(
RESEARCH_EVIDENCE_SKILL,
"Separate observation, contradiction, inference, and missing evidence",
&research_surface,
"Separate observations, contradictions, inferences, and missing evidence",
);
assert_contains(RESEARCH_EVIDENCE_SKILL, "`research_evidence`");
assert_contains(RESEARCH_OPTIONS_SKILL, "status quo");
assert_contains(RESEARCH_OPTIONS_SKILL, "evidence-grounded");
assert_contains(RESEARCH_OPTIONS_SKILL, "`research_options`");
assert_contains(RESEARCH_JUDGMENT_SKILL, "challenge-ready");
assert_contains(RESEARCH_JUDGMENT_SKILL, "stable judgment id or hash");
assert_contains(RESEARCH_JUDGMENT_SKILL, "not-decision-ready");
assert_contains(&research_surface, "`research_evidence`");
assert_contains(&research_surface, "status quo");
assert_contains(&research_surface, "evidence");
assert_contains(&research_surface, "`research_options`");
assert_contains(&research_surface, "challenge-ready");
assert_contains(&research_surface, "stable judgment id or hash");
assert_contains(&research_surface, "not_decision_ready");
assert_contains(
RESEARCH_CHALLENGE_SKILL,
&research_surface,
"Do not finalize `decision_ready` while material objections remain unresolved",
);
assert_contains(RESEARCH_CHALLENGE_SKILL, "skeptic worker");
assert_contains(RESEARCH_DECISION_SKILL, "Use exactly one terminal outcome");
assert_contains(RESEARCH_DECISION_SKILL, "No unresolved decisions, evidence gaps, or blockers");
assert_contains(RESEARCH_DECISION_SKILL, "Promotion is a separate authority step");
assert_contains(RESEARCH_PROMOTE_SKILL, "research-to-planning authority boundary");
assert_contains(RESEARCH_PROMOTE_SKILL, "Do not infer acceptance");
assert_contains(RESEARCH_PROMOTE_SKILL, "Program Intake");
assert_contains(&research_surface, "skeptic worker");
assert_contains(&research_surface, "Use exactly one terminal outcome");
assert_contains(&research_surface, "No unresolved decisions, evidence gaps, or blockers");
assert_contains(&research_surface, "Promotion is a separate authority step");
assert_contains_normalized(&research_surface, "research-to-planning authority boundary");
assert_contains(&research_surface, "Do not infer acceptance");
assert_contains(&research_surface, "Program Intake");
}

fn assert_contains(haystack: &str, needle: &str) {
Expand Down
12 changes: 6 additions & 6 deletions plugins/decodex/.codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "decodex",
"version": "0.2.0",
"description": "Agent-facing workflows for Decodex bounded research, Decision Contract promotion, planning, manual CLI use, and runtime-owned automation.",
"description": "Decodex agent workflows.",
"author": {
"name": "hack-ink",
"email": "hi@hack.ink",
Expand All @@ -20,8 +20,8 @@
"skills": "./skills/",
"interface": {
"displayName": "Decodex",
"shortDescription": "Use Decodex for bounded research, Decision Contract promotion, planning, manual CLI work, or retained-lane automation.",
"longDescription": "Routes Codex agents through Decodex natural-language-first bounded research, such as \"research X\", with probe, evidence, options, judgment, challenge, and decision gates that produce latent Decision Contracts before execution. Follow-ups such as \"arrange this\" or \"推进\" can promote accepted work into planning and Program Intake where ready mapped nodes dispatch directly, while graph, DAG, goal, and dispatch mechanics backstage remain hidden from ordinary users.",
"shortDescription": "Research, plan, and operate Decodex.",
"longDescription": "Routes Decodex research, promotion, planning, CLI, labels, commit, landing, and automation.",
"developerName": "hack-ink",
"category": "Development",
"capabilities": [
Expand All @@ -32,9 +32,9 @@
"privacyPolicyURL": "https://github.com/hack-ink/decodex",
"termsOfServiceURL": "https://github.com/hack-ink/decodex",
"defaultPrompt": [
"Research how Decodex should handle this.",
"Arrange the accepted Decodex research contract into executable issues.",
"Use Decodex to inspect this lane."
"Research this with Decodex.",
"Arrange accepted research.",
"Inspect this Decodex lane."
],
"brandColor": "#0F766E"
}
Expand Down
141 changes: 141 additions & 0 deletions plugins/decodex/references/research-method.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# Decodex Research Method Reference

Use this reference when Decodex research needs the full Decision Contract protocol.
Decodex is the default research surface for bounded technical investigation.

## Loop

Run the same decision-quality loop for bounded research:

1. Probe: frame the decision, scope, success criteria, constraints, stop rule,
hypotheses, rival hypotheses, and falsifiers.
2. Evidence: collect traceable observations, contradictions, inferences, source
references, missing evidence, and private/public provenance.
3. Options: compare realistic choices, including status quo, minimal patch,
architecture redesign, staged migration, and explicit no-go/defer when relevant.
4. Judgment: form one challenge-ready recommendation or an explicit non-decision.
5. Challenge: attack the judgment with skeptic objections.
6. Decision: finish as exactly one terminal status.
7. Promote: only after explicit acceptance.

The compact phase order is: probe, evidence, options, judgment, challenge, decision,
promote.

## Probe Checklist

Record these before broad search or implementation:

- decision question
- in-scope and out-of-scope surfaces
- success criteria and acceptance threshold
- constraints and non-goals
- stop rule or budget
- primary hypothesis
- realistic rival hypotheses
- falsifiers for the primary hypothesis
- initial evidence plan

The first durable event for machine-authored runs is `probe_completed`.

## Evidence Rules

- No evidence, no claim.
- Keep source or code references close to each claim.
- Separate observations, contradictions, inferences, and missing evidence.
- Prefer primary sources for code, APIs, specifications, policies, and live project
state.
- Preserve conflicting evidence and name what would resolve it.
- Use private evidence refs for local, sensitive, or runtime-private proof.
- Map supported claims into `research_evidence`.

## Option Rules

For each option, record:

- what changes
- supporting evidence
- tradeoffs and risks
- what becomes easier or harder
- why the option is selected or rejected

Do not compare straw-man options or select an option without evidence or explicit
assumptions.
Map option records into `research_options`.

## Judgment Rules

A challenge-ready judgment includes:

- recommended option or explicit non-decision outcome
- why it best satisfies the decision criteria
- evidence ids, source references, or code references
- assumptions and constraints
- rejected alternatives
- unresolved evidence gaps
- expected validation if promoted

Do not call the judgment final before challenge.
For replayable machine-authored runs, assign a stable judgment id or hash over the
normalized conclusion and cited evidence.

## Challenge Rules

Challenge the judgment against:

- missing or contradictory evidence
- unexamined alternatives
- scope creep
- hidden operational cost
- compatibility or migration risk
- security, privacy, data, billing, or destructive-action risk
- authority mismatch
- validation gaps

Record each objection as resolved, unresolved, or out of scope. Unresolved material
objections block `decision_ready`.
Use a bounded skeptic worker only when it materially improves independence.

## Decision Statuses

Use exactly one terminal outcome:

- `decision_ready`: evidence, options, resolved challenge, objectives, validation,
and proposed issue summaries are sufficient for issue shaping after promotion.
- `not_decision_ready`: useful evidence exists, but a decision would be unsafe or
under-supported.
- `blocked`: research cannot proceed until a non-decision blocker is removed.
- `needs_human_decision`: remaining uncertainty is a human/product/authority choice.

Never use `decision_ready` because budget ended.
No unresolved decisions, evidence gaps, or blockers may remain for `decision_ready`.

## Decision Contract Shape

The durable output is a `decodex.decision_contract/1` payload retained in runtime
state. In chat, present the same shape plainly:

- source intent and decision question
- evidence and provenance
- realistic options and tradeoffs
- selected decision or why no safe decision exists
- assumptions, constraints, non-goals, objections, and stop conditions
- validation expectations
- proposed issue summaries only when downstream work is appropriate
- unresolved decisions, evidence gaps, or blockers

## Promotion Boundary

Research output is latent. Promotion requires explicit acceptance or an equivalent
follow-up such as "arrange this", "push this forward", "推进", or "做".
Promotion is a separate authority step and the research-to-planning authority
boundary.

When promoting:

1. Identify the accepted contract.
2. Preserve its objectives, non-goals, constraints, assumptions, objections,
validation expectations, proposed issue summaries, and stop conditions.
3. Refuse promotion when unresolved decisions, evidence gaps, or blockers remain.
4. Route accepted work to `planning`.
5. Let Program Intake persist Execution Program readiness and dispatch ready mapped
nodes directly.
Loading