Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
5813ee1
feat(agent-runtime): add immutable procedural guidance and offline ca…
seonghobae Sep 9, 2026
a351bff
docs(agent-runtime): satisfy procedural public API contracts
seonghobae Sep 9, 2026
468bbdf
fix(agent-runtime): allocate fresh procedural ADR identity
seonghobae Sep 10, 2026
781fd81
fix(agent-runtime): remove conflicting procedural ADR identity
seonghobae Sep 10, 2026
5623f83
docs(agent-runtime): bind procedural plan to ADR-0017
seonghobae Sep 10, 2026
63c8a81
docs(agent-runtime): record procedural graph behavior
seonghobae Sep 10, 2026
8437998
test(agent-runtime): require runtime brand for procedural sessions
seonghobae Sep 10, 2026
9056eb2
fix(agent-runtime): brand admitted procedural sessions
seonghobae Sep 10, 2026
a99b861
fix(agent-runtime): retain canonical execution identities in procedur…
seonghobae Sep 10, 2026
80f96ae
merge: reconverge procedural graph on protected documentation authority
seonghobae Sep 10, 2026
a46ee0a
docs(architecture): bound procedural graph candidate authority
seonghobae Sep 10, 2026
f5f83c6
docs(traceability): bind procedural graph evidence and non-authority
seonghobae Sep 10, 2026
e451da7
docs(prd): define procedural graph advisory product boundary
seonghobae Sep 10, 2026
ef6e97d
docs(trd): specify procedural graph runtime contracts
seonghobae Sep 10, 2026
368b917
docs(uml): model procedural graph advisory boundaries
seonghobae Sep 10, 2026
ae9a289
docs(test): cover procedural graph advisory invariants
seonghobae Sep 10, 2026
892f392
docs(operability): keep procedural guidance non-activated
seonghobae Sep 10, 2026
8b63edb
docs(gaps): register procedural graph activation boundary
seonghobae Sep 10, 2026
a91098e
test(docs): align dated protected observation
seonghobae Sep 10, 2026
0ee2992
test(docs): stop pinning dated observation SHA
seonghobae Sep 10, 2026
4707f0a
test(agent-runtime): reject caller-branded procedural errors
seonghobae Sep 10, 2026
bed1629
fix(agent-runtime): keep procedural error provenance module-owned
seonghobae Sep 10, 2026
4d3e387
test(agent-runtime): reject caller-minted procedural error text
seonghobae Sep 10, 2026
33673d3
fix(agent-runtime): close procedural error-code minting
seonghobae Sep 10, 2026
ae14a17
docs(agent-runtime): reconcile procedural verification record
seonghobae Sep 10, 2026
58ec47e
docs(agent-runtime): restore TRD reference authority
seonghobae Sep 10, 2026
aa954e6
docs(agent-runtime): own procedural adoption evidence in parent
seonghobae Sep 10, 2026
c016ee1
test(docs): keep procedural adoption evidence parent-local
seonghobae Sep 10, 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
151 changes: 151 additions & 0 deletions docs/adr/0016-procedural-graph-guidance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# ADR-0016: Advisory procedural graphs with offline candidate screening

Status: Proposed. A source implementation on a feature branch is not protected-source,
release, or deployment acceptance.

Date: 2026-09-10

Tracking: [CWL adoption](https://github.com/ContextualWisdomLab/.github/issues/2067),
[Noema implementation](https://github.com/ContextualWisdomLab/noema/issues/584).

## Context and alternatives

Lu et al., *Procedural Graphs: Self-Evolving Execution Structures for LLM Agents*,
[arXiv:2609.09153v1](https://arxiv.org/html/2609.09153v1), sections 3.1–3.3,
externalizes procedural knowledge as procedure/relation/procedure triples. Local
subgraphs inform the solver; offline edits are checked on held-out tasks and rejected
edits retained. The graph stays fixed during an execution. This is a method reference,
not CWL benchmark evidence or permission to modify production controls. The adoption
request originated in [this article](https://conanssam.com/posts/2026-09-10-procedural-graphs-self-evolving-llm-agents).

Keeping only longer prose playbooks loses explicit connectivity. Replacing every
workflow with a self-editing hard controller would conflate advice with authority and
duplicate existing policy, tool, and lifecycle owners. Choose a small advisory value
and evidence-screening port within Noema's Agent Runtime bounded context instead.

## Decision and owned implementation

`src/agent-runtime/procedural-graph.ts` owns an immutable graph and a closure pinned
to an execution ID and exact graph digest. `procedural-evolution.ts` screens supplied
paired evaluation evidence. `procedural-input.ts` shares only strict data readers and
content hashing inside this aggregate; it is not a generic organization utility.
No HTTP route, `/exchange` change, OIDC trust expansion, persistence binding,
provider client, credential, package dependency, or workflow is introduced.

The local schema is `noema.procedural-graph/v1`, not a released CWL wire contract.
Nodes have canonical identifiers, including `Start`. Directed edges carry `from`,
`relation`, `to`, `condition`, `guidance`, and `pitfalls`; supported relation labels
are `leads_to`, `requires`, and `enables`. Labels and text are advisory data, not
executable conditions or a dependency scheduler. Cycles and isolated nodes are
permitted; product-specific terminal reachability and cycle policy need a later
profile validator. Unknown fields, duplicate nodes/triples, missing endpoints,
accessors, sparse arrays, and malformed identities fail closed.

Bounds are 256 nodes, 512 edges, 128-character identifiers, 2048 UTF-16 code units
per text field, and 1 MiB per hashed serialization. Canonical JSON key order and
sorted nodes/triples define this local implementation's digest; this is not a claim
of RFC 8785/JCS interoperability. Full identity includes tenant, task, graph ID,
revision, parent digest, and content. The structure digest excludes revision and
parent only. All raw fields are copied before asynchronous hashing and deep-frozen.
Deserialized objects must be reconstructed and rehashed, not cast to trusted values.

`startProceduralSession` requires an exact tenant/task/digest match and pins the
selected graph for the caller's execution. It does not authenticate a tenant or
register an execution: the trusted caller must do that. Each `context` request must
supply `lastProcedure`, `hops` (1–4), and `maxEdges` (1–512). Null procedure selects
`Start`; two hops is the initial consumer recommendation, not a universal optimum.
Traversal follows outgoing edges and terminates safely on cycles. Unknown nodes or
an exceeded edge budget produce an empty `abstain` result rather than the paper's
full-graph fallback or a silently truncated prerequisite set. This intentional
CWL adaptation needs comparison in the shadow pilot.

Every context says `authority: advisory_only`. Text may still contain hostile
instructions or sensitive content; this module is neither a prompt-injection
classifier nor a secret/PII scrubber. Admission, minimization, taint handling,
external-instruction precedence, tool allowlists, policy approval, tenant auth,
cancellation, and side-effect idempotency remain enforced outside the graph.

## Offline evidence screening

`assessProceduralCandidate` accepts two admitted graphs, a pre-registered evaluation
plan, two receipts, and scoped rejected keys. Candidate tenant/task/graph identity,
parent digest, and exactly-next revision must match the retained base. Receipts
must name those exact graph digests and the same evaluation-context digest.
The validator owner defines and authenticates that context, including dataset
version, model, decoding, tools, metric/rubric, execution environment, and protocol.
This module validates equality and shape, not issuer signatures or semantic
completeness of that digest. Unauthenticated client receipts cannot be activation
or governance evidence.

Training and held-out IDs must be disjoint, unique, and bounded to 10,000 per list.
Both receipt case sets must equal the complete registered holdout; scores must be
finite numbers in [0,1]. The externally selected minimum case count is enforced.
There is no default claim that two or any other small number of cases proves
validity. Missing cases, changed contexts, or non-finite scores are errors.

Unchanged content and previously rejected content are ineligible. Any reported
candidate safety violation is ineligible even if its mean score rises. Otherwise,
the candidate's paired-case mean must not decrease. This deterministic screening
rule is not statistical significance, a noninferiority study, calibrated evaluation,
or evidence that every subgroup/metric is non-regressing. Those gates belong to the
evaluation profile and independent validator. Repeated validation feedback can
still overfit: the final test set must stay untouched by the refiner and promotion
search, with independent confirmation before deployment.

The rejection signature binds the exact base digest, candidate structure,
evaluation context, minimum count, and canonical training/holdout partition.
Array reordering cannot evade a recorded rejection; changed evaluation conditions
do not inherit a global blacklist. Returning a key does not persist it, and does
not disclose holdout examples to a refiner. The later State/Checkpoint adapter
owns authenticated retention and versioned rejection history.

Even a passing result returns `activationAuthorized: false`. `eligibleForApproval`
means only that supplied evidence passed this local screening. It cannot publish,
activate, invoke tools, bypass review, edit policies, or grant credentials. Promotion
requires independent approval tied to graph/evidence digests, policy/security
checks, compare-and-swap against the retained head, rollback, and revocation.
Existing executions must keep their pinned revision and separately honor revocation.

## CWL ownership and rollout

| Owner | Planned responsibility; not a claim of deployed integration |
| --- | --- |
| Noema | Graph snapshot, guidance context, offline screening; later lifecycle/state adapters |
| context-graph-contracts | Released language-neutral schemas, digest rules, conformance fixtures |
| enterprise-architecture-core | Capability/owner map, versioned adoption matrix and evidence classes |
| contextual-orchestrator | Existing gateway routing for later guide/solver/refiner calls; no client-side provider fallback |
| keyverse | Credential authority; graph/evaluation records contain no raw credential values or `.env` dependency |
| PolicyWeave, governance-risk-compliance, Noema Policy/Approval | Separate policy truth, risk/evidence, and approval boundaries |
| appguardrail, quarantine-sandbox-runtime, EgressWeave, wardnet | Existing detection, isolation, outbound, and endpoint control ownership |
| OriginWeave, LineageWeave | Sanitized observations and immutable provenance references, not copied foreign truth |
| psychometrics-commons / evaluation owner | Task-specific measures, rubric and standard-setting separation, held-out protocol and uncertainty |
| .github and product owners | Central development profile and product-specific procedural graphs/adapters/tests |

1. Implement and review this deterministic core without enabling a production path.
2. Have contract/EAC owners release interoperable schemas and ownership records.
Do not consume mutable sibling PR heads or independently copy this runtime.
3. Integrate read-only shadow guidance through the existing orchestrator boundary
in the central development loop and Naruon. Compare no graph, fixed graph, and
evolved graph under matched conditions. Measure task success, sequence errors,
duplicate effects, tokens/cost, and latency separately; do not invent gains.
4. Add sanitized trajectory extraction, offline candidate generation, authenticated
receipt verification, persistent rejection memory, CAS promotion and recovery.
5. Enable opt-in canaries for other products only after their own conformance and
rollback evidence. Accounting postings, billing, employment assessment, data
deletion and deployment retain their independent high-risk approval controls.

Do not force this pattern into deterministic numerical kernels or create another
central scheduler. Source adoption, shadow use, canary, active deployment, and
rollback-tested operation must appear as separate states in the adoption matrix.
The active documentation lane may reconcile the ADR index and PRD/TRD/traceability
without this lane overwriting its root baseline or historical evidence.

## Acceptance and remaining limitations

The focused tests exercise the pure boundary; native repository typecheck,
repository-wide exact coverage, inherited security checks, independent review,
release artifacts, and deployed operational evidence remain distinct requirements.
See the [implementation plan and verification record](../superpowers/plans/2026-09-10-procedural-graphs.md).
No automatic LLM refiner, signed graph store, guidance prompt, MCP endpoint,
production caller integration, or organization-wide deployment is delivered by
this first source slice.
135 changes: 135 additions & 0 deletions docs/superpowers/plans/2026-09-10-procedural-graphs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# Procedural graph core implementation plan and verification record

Goal: make advisory procedural structure and offline candidate screening available
as testable Noema Agent Runtime ports without changing production authority.

Architecture: local immutable graph values; an execution-pinned read-only context;
independent pure evidence screening. Foreign policy, credentials, routing, and
product truth remain outside this aggregate.

Spec: [ADR-0016](../../adr/0016-procedural-graph-guidance.md).
Tracking: Noema #584; ContextualWisdomLab/.github #2067.

## Scope and interfaces

| File | Responsibility |
| --- | --- |
| `src/agent-runtime/procedural-input.ts` | Internal descriptor-safe readers, bounds, canonical hashing and fixed errors |
| `src/agent-runtime/procedural-graph.ts` | `createProceduralGraph(input)` and `startProceduralSession(graph, scope)` |
| `src/agent-runtime/procedural-evolution.ts` | `assessProceduralCandidate(input)` returns eligibility, never activation |
| `test/procedural-graph.test.mjs` | Immutable graph, scope, traversal, malformed/hostile input regressions |
| `test/procedural-evolution.test.mjs` | Paired evidence, lineage, partition, safety and rejection regressions |

No edits to package/lock files, workflows, `/exchange`, runtime trust pins,
existing execution/extension lifecycle code, AGENTS, or the active #583 baseline
lane. The input helper is an additional new path within #584's aggregate, not a
second shared-kernel owner. No sibling repository source is copied or mutated.

## Execution and test sequence

- [x] Read live protected Noema architecture, Agent Runtime code, package/test
configuration, active PRs, and central ownership conventions.
- [x] Register the organization plan and isolated implementation lane.
- [x] Write behavior assertions before implementation. Interface-only scaffolds
returned empty values; the first run failed on missing actual behavior.
- [x] Implement immutable graph admission and directed bounded context traversal.
- [x] Implement matched held-out screening and context-bound rejection signatures.
- [x] Add hostile thrown-proxy and actual-partition identity regressions. Both
failed before their causal fixes, while the other behavior stayed passing.
- [x] Normalize errors by locally created-error membership instead of invoking an
untrusted thrown object's prototype. Bind rejection identity to the actual
case partition/minimum count as well as the evaluator's context digest.
- [x] Re-run all focused assertions and strict standalone TypeScript compilation.
- [ ] Run unchanged native repository typecheck and full Vitest coverage on the
exact PR head using its pinned toolchain; resolve any observed failures.
- [ ] Obtain all live required checks and independent review on that same head.
- [ ] Merge through protected governance; release/shared-contract and deployed
integration acceptance remain separate follow-on work.

## Minimal local call sequence

```ts
import {createProceduralGraph, startProceduralSession} from "../../../src/agent-runtime/procedural-graph";

const graph = await createProceduralGraph({
schemaVersion: "noema.procedural-graph/v1",
tenantId: "tenant-a", taskType: "pr-repair", graphId: "review-loop",
revision: 1, parentDigest: null,
nodes: ["Start", "review", "verify"],
edges: [
{from: "Start", relation: "leads_to", to: "review", condition: "",
guidance: "Read exact-head review evidence", pitfalls: "Do not reuse stale checks"},
{from: "review", relation: "leads_to", to: "verify", condition: "",
guidance: "Verify the finding against source", pitfalls: "A model opinion is not proof"},
],
});
const session = startProceduralSession(graph, {
tenantId: "tenant-a", taskType: "pr-repair", executionId: "run-1",
graphDigest: graph.digest,
});
const context = session.context({lastProcedure: null, hops: 2, maxEdges: 64});
// A trusted caller may use context as advisory data; it grants no tool authority.
```

The complete executable candidate/receipt examples are the fixture and assertions
in `test/procedural-evolution.test.mjs`. They use synthetic normalized scores and
are not CWL product-performance evaluation results.

## Verification actually performed in the authoring environment

The authoring container had Node 22.16.0 and TypeScript 5.8.3; it could not resolve
GitHub/package-host DNS and did not contain Vitest or the full repository checkout.
Live repository reads/writes used the connected GitHub API. The pinned repository
toolchain observed at the branch point is Node 24.19.0 / npm 11.17.0; it was not
replaced, weakened, or installed by this change.

The three new source files compiled with strict TypeScript, ES2022 target and
CommonJS output. Test assertions were copied unchanged to a local adapter,
replacing only `vitest` with `node:test` and `.ts` source imports with compiled
`.js` paths. This ran **89 tests: 89 passed, 0 failed, 0 skipped**. Node's coverage
report for the three compiled production modules showed 100% lines, branches,
and functions. This is scoped compiled-module evidence, not native Vitest
statement/branch coverage, Cloudflare compatibility, repository-wide coverage,
security-scanner success, or hosted exact-head approval. No coverage configuration
or threshold changed.

Native commands for the exact PR checkout, under the repository-pinned toolchain:

```sh
npm ci
npm run typecheck
npm test
```

For faster diagnosis only, before the unchanged full gate:

```sh
npx --no-install vitest run test/procedural-graph.test.mjs test/procedural-evolution.test.mjs
```

A focused pass never replaces the required full gate. Subsequent PR pushes must
rerun relevant evidence; authored local measurements are not transferable to a
later head, release, deployment, or different runtime.

## Downstream acceptance work

Contract owner: release graph/context/evaluation/decision schemas with equivalent
canonicalization fixtures across languages. Graph hashes here are local, not a
published interchange guarantee.

Runtime/model integration owner: authenticate scope and artifacts, preserve graph
revision for the entire execution, call the existing orchestrator gateway, treat
all guidance text as untrusted advice, and reject tool authority inferred from it.

Evaluation owner: pre-register task-specific criteria and minimum evidence,
authenticate issuer/context/case receipts, exclude training/final-test leakage,
measure uncertainty and subgroup/control regressions independently, and do not
promote from this arithmetic screen alone.

State/Approval owner: persist scoped rejections without leaking holdout content,
require independent exact-digest approval and immutable foreign-owner evidence,
perform CAS promotion and tested rollback/revocation, and keep acknowledged history.

Product owners: demonstrate actual shadow use, per-domain controls and consumer
conformance before opt-in activation. A tracked issue is not implementation or
deployment evidence.
Loading
Loading