ennodia 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +2 -19
- package/README.md +4 -6
- package/docs/comparisons/agent-frameworks.md +5 -5
- package/docs/comparisons/autogen.md +4 -4
- package/docs/comparisons/chathub.md +4 -4
- package/docs/comparisons/index.md +4 -4
- package/docs/comparisons/langgraph.md +4 -4
- package/docs/comparisons/mixture-of-agents.md +5 -5
- package/docs/comparisons/model-merging.md +5 -5
- package/docs/comparisons/openrouter.md +4 -4
- package/docs/concepts/compositional-audits.md +8 -6
- package/docs/concepts/data-governance.md +5 -9
- package/docs/concepts/how-ennodia-works.md +2 -2
- package/docs/concepts/interfaces-and-core.md +1 -1
- package/docs/concepts/second-opinions.md +5 -5
- package/docs/evidence/index.md +6 -13
- package/docs/evidence/measurement.md +6 -5
- package/docs/getting-started.md +9 -6
- package/docs/guides/agent-skills.md +6 -5
- package/docs/guides/budgets-and-limits.md +8 -6
- package/docs/guides/pragmatic-mode.md +2 -0
- package/docs/guides/recipes.md +1 -4
- package/docs/guides/running-better-audits.md +7 -7
- package/docs/guides/troubleshooting.md +0 -2
- package/docs/guides/understand-results.md +0 -2
- package/docs/index.md +2 -4
- package/docs/install.md +11 -9
- package/docs/reference/controlled-english.md +1 -3
- package/docs/reference/ennodia-io.md +7 -7
- package/docs/reference/mcp-tools.md +69 -15
- package/docs/reference/supported-harnesses.md +9 -4
- package/docs/roadmap.md +0 -2
- package/package.json +3 -10
- package/skills/pragmatic/SKILL.md +2 -0
- package/src/cli.ts +31 -15
- package/src/compare.ts +37 -1
- package/src/core.ts +2 -4
- package/src/diagnosis.ts +48 -1
- package/src/harnesses.ts +54 -25
- package/src/index.ts +4 -0
- package/src/runs.ts +17 -8
- package/src/server.ts +55 -2
- package/src/tasks.ts +145 -37
- package/src/version.ts +1 -1
- package/bench/README.md +0 -34
- package/bench/bug-recall/run.ts +0 -339
- package/bench/bug-recall/scorer.ts +0 -424
- package/bench/fixtures/bug-recall/001-missing-await/input.ts +0 -33
- package/bench/fixtures/bug-recall/001-missing-await/oracle.json +0 -28
- package/bench/fixtures/bug-recall/001-missing-await/responses/claude-code-solo.md +0 -1
- package/bench/fixtures/bug-recall/001-missing-await/responses/codex-solo.md +0 -1
- package/bench/fixtures/bug-recall/001-missing-await/responses/ennodia-parallel-compare.md +0 -1
- package/bench/fixtures/bug-recall/002-timeout-drain/input.ts +0 -40
- package/bench/fixtures/bug-recall/002-timeout-drain/oracle.json +0 -28
- package/bench/fixtures/bug-recall/002-timeout-drain/responses/claude-code-solo.md +0 -1
- package/bench/fixtures/bug-recall/002-timeout-drain/responses/codex-solo.md +0 -1
- package/bench/fixtures/bug-recall/002-timeout-drain/responses/ennodia-parallel-compare.md +0 -1
- package/bench/fixtures/bug-recall/003-schema-contract/input.ts +0 -22
- package/bench/fixtures/bug-recall/003-schema-contract/oracle.json +0 -28
- package/bench/fixtures/bug-recall/003-schema-contract/responses/claude-code-solo.md +0 -1
- package/bench/fixtures/bug-recall/003-schema-contract/responses/codex-solo.md +0 -1
- package/bench/fixtures/bug-recall/003-schema-contract/responses/ennodia-parallel-compare.md +0 -1
- package/bench/fixtures/bug-recall/004-cancel-propagation/input.ts +0 -28
- package/bench/fixtures/bug-recall/004-cancel-propagation/oracle.json +0 -28
- package/bench/fixtures/bug-recall/004-cancel-propagation/responses/claude-code-solo.md +0 -1
- package/bench/fixtures/bug-recall/004-cancel-propagation/responses/codex-solo.md +0 -1
- package/bench/fixtures/bug-recall/004-cancel-propagation/responses/ennodia-parallel-compare.md +0 -1
- package/bench/results/.gitkeep +0 -1
- package/docs/evidence/building-ennodia.md +0 -66
- package/docs/evidence/docs-drift.md +0 -73
- package/docs/evidence/skill-trial.md +0 -68
- package/docs/reference/benchmarks.md +0 -64
- package/examples/docs-drift/README.md +0 -8
- package/examples/docs-drift/archive/migration.md +0 -4
- package/examples/docs-drift/check.ts +0 -7
- package/examples/docs-drift/config.ts +0 -8
- package/examples/docs-drift/demo.ts +0 -54
- package/examples/docs-drift/recorded-run.json +0 -16
- package/examples/skill-trial/README.md +0 -8
- package/examples/skill-trial/check.ts +0 -15
- package/examples/skill-trial/contract.md +0 -7
- package/examples/skill-trial/recorded-trial.json +0 -42
- package/examples/skill-trial/retry.ts +0 -4
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"id": "004-cancel-propagation",
|
|
3
|
-
"title": "Run cancellation does not cancel child tasks",
|
|
4
|
-
"prompt": "Review the TypeScript fixture and list correctness bugs.",
|
|
5
|
-
"requiredFindings": [
|
|
6
|
-
{
|
|
7
|
-
"id": "missing-task-cancel-call",
|
|
8
|
-
"severity": "high",
|
|
9
|
-
"line": 20,
|
|
10
|
-
"description": "The loop finds running child tasks but never calls task.cancel(), leaving them running after the run is cancelled.",
|
|
11
|
-
"keywords": ["task.cancel", "running"]
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
"id": "mutates-run-in-place",
|
|
15
|
-
"severity": "medium",
|
|
16
|
-
"line": 17,
|
|
17
|
-
"description": "The function mutates the Run object in place before child task cancellation has succeeded, so callers can observe cancelled state while children continue running.",
|
|
18
|
-
"keywords": ["mutates", "cancelled", "children"]
|
|
19
|
-
}
|
|
20
|
-
],
|
|
21
|
-
"knownFalsePositives": [
|
|
22
|
-
{
|
|
23
|
-
"id": "task-id-order",
|
|
24
|
-
"description": "Claims task ID order causes the cancellation bug.",
|
|
25
|
-
"terms": ["taskIds", "order"]
|
|
26
|
-
}
|
|
27
|
-
]
|
|
28
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"findings":[{"line":20,"summary":"The loop checks each running task but never calls task.cancel, so children keep running after cancellation."}]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"findings":[{"line":17,"summary":"The run is mutated to cancelled before children are cancelled, so callers can observe cancelled while children still run."}]}
|
package/bench/fixtures/bug-recall/004-cancel-propagation/responses/ennodia-parallel-compare.md
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"findings":[{"line":20,"summary":"The loop finds running child tasks but never calls task.cancel, leaving running tasks alive."},{"line":17,"summary":"cancelRun mutates the run to cancelled before child cancellation succeeds, so children can continue running under a cancelled run."}]}
|
package/bench/results/.gitkeep
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Building Ennodia with Ennodia
|
|
3
|
-
description: A real development case with a failed launch, a useful worker patch, and primary-agent review.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Building Ennodia with Ennodia
|
|
7
|
-
|
|
8
|
-
Development record: September 6, 2026. These changes belong to the next release candidate.
|
|
9
|
-
|
|
10
|
-
A local server could accept browser requests that started agent work without an intended origin check.
|
|
11
|
-
The primary agent had a reproduced defect and a focused implementation task.
|
|
12
|
-
It stayed in Codex and used Ennodia to dispatch the work.
|
|
13
|
-
|
|
14
|
-
## What happened
|
|
15
|
-
|
|
16
|
-
| Attempt | Observed result | Next action |
|
|
17
|
-
| --- | --- | --- |
|
|
18
|
-
| Claude Code with Sonnet | Authentication failed before the task ran. | Use another configured agent. |
|
|
19
|
-
| OpenCode with its configured model | Reproduced the problem, edited four files, and added seven regression tests. | Review the patch in the primary conversation. |
|
|
20
|
-
| Primary agent | Tightened malformed Host and Origin validation and preserved the native request size limit. | Run the combined verification suite. |
|
|
21
|
-
|
|
22
|
-
The worker tested both the request handler and a real listening server.
|
|
23
|
-
It also found that Bun can return an empty oversized-request error before the handler runs.
|
|
24
|
-
Its proposed size-limit adjustment could not guarantee a structured response for every oversized request.
|
|
25
|
-
The primary agent kept the hard limit and documented the actual behavior.
|
|
26
|
-
|
|
27
|
-
The combined suite passed after integration.
|
|
28
|
-
This demonstrates a useful contribution that still needed review and adaptation.
|
|
29
|
-
It does not establish how long the primary agent alone would have taken.
|
|
30
|
-
|
|
31
|
-
## What did not help
|
|
32
|
-
|
|
33
|
-
A separate Compare review used a smaller GPT model with the rigorous-review skill.
|
|
34
|
-
It reached the ten-minute task limit without returning a usable proposal.
|
|
35
|
-
The primary agent completed those fixes locally.
|
|
36
|
-
The record includes that failed attempt, rather than treating every delegation as a success.
|
|
37
|
-
|
|
38
|
-
The Claude failure indicates an expired login, not model quality.
|
|
39
|
-
The GPT attempt does not establish that the model or skill is generally unsuitable.
|
|
40
|
-
Its observed result applies to this task, configuration, and time limit.
|
|
41
|
-
|
|
42
|
-
A later broad documentation assignment through OpenCode also reached its ten-minute limit without producing edits.
|
|
43
|
-
The primary agent completed those pages directly.
|
|
44
|
-
This suggests testing smaller assignments and clearer execution controls. It does not establish a general provider limitation.
|
|
45
|
-
|
|
46
|
-
## Inspect and reproduce
|
|
47
|
-
|
|
48
|
-
The implementation and regressions are in the open repository:
|
|
49
|
-
|
|
50
|
-
- [HTTP implementation](https://github.com/cherninlab/ennodia/blob/main/packages/ennodia-io/src/io.ts)
|
|
51
|
-
- [HTTP regressions](https://github.com/cherninlab/ennodia/blob/main/packages/ennodia-io/src/io.test.ts)
|
|
52
|
-
|
|
53
|
-
Use the release candidate checkout that contains this page.
|
|
54
|
-
|
|
55
|
-
```sh
|
|
56
|
-
bun install
|
|
57
|
-
bun test packages/ennodia-io/src/io.test.ts
|
|
58
|
-
bun run verify
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
The tests use local fixtures. They do not call model providers.
|
|
62
|
-
A live repeat requires an authenticated supported agent.
|
|
63
|
-
Save the worker output and the primary agent’s final diff when repeating the experiment.
|
|
64
|
-
|
|
65
|
-
The practical benefit here was a reviewed contribution from another tool without moving the primary conversation.
|
|
66
|
-
No token-saving or speed comparison was measured.
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Find stale documentation
|
|
3
|
-
description: Review current documentation without deleting useful historical records.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Find stale documentation
|
|
7
|
-
|
|
8
|
-
A current guide can disagree with code while a historical document remains correct for its period.
|
|
9
|
-
This exercise gives an additional agent a bounded review task.
|
|
10
|
-
|
|
11
|
-
The fixture lives in `examples/docs-drift` in the Ennodia checkout.
|
|
12
|
-
It contains deliberate documentation errors and a labeled migration record.
|
|
13
|
-
|
|
14
|
-
## Try it
|
|
15
|
-
|
|
16
|
-
The recording below shows an actual MCP run from the release candidate checkout.
|
|
17
|
-
The final frame includes ten extra seconds for reading.
|
|
18
|
-
|
|
19
|
-
<video controls preload="metadata" aria-label="Recorded Ennodia documentation review" style="width:100%; height:auto;" src="/demos/docs-drift.mp4"></video>
|
|
20
|
-
|
|
21
|
-
The [terminal recording](/demos/docs-drift.cast) preserves the captured output and timing.
|
|
22
|
-
The text below provides the same findings without video.
|
|
23
|
-
|
|
24
|
-
1. Use a local checkout of Ennodia.
|
|
25
|
-
2. Run the fixture’s behavior check.
|
|
26
|
-
|
|
27
|
-
```sh
|
|
28
|
-
bun examples/docs-drift/check.ts
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
3. Give this request to your primary agent.
|
|
32
|
-
|
|
33
|
-
```text
|
|
34
|
-
Use Ennodia MCP to review examples/docs-drift in a separate read-only task.
|
|
35
|
-
Compare the current README with config.ts. Identify each conflicting claim.
|
|
36
|
-
Distinguish current instructions from the labeled historical migration record.
|
|
37
|
-
Return proposed corrections with file references. Bring the findings back here.
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
4. Review each proposed correction against the source.
|
|
41
|
-
5. Update the current guide in your copy.
|
|
42
|
-
6. Keep the historical migration record labeled as history.
|
|
43
|
-
|
|
44
|
-
## Check the result
|
|
45
|
-
|
|
46
|
-
The current implementation uses port `4545`, the variable `APP_PORT`, and the response `{ "ready": true }`.
|
|
47
|
-
The README contains three conflicting current claims.
|
|
48
|
-
The migration record describes the previous release and does not need the same changes.
|
|
49
|
-
|
|
50
|
-
A useful review finds the three conflicts and preserves the historical distinction.
|
|
51
|
-
A model can still miss a conflict or recommend deleting useful history.
|
|
52
|
-
This exercise has known answers. It is not a general benchmark.
|
|
53
|
-
|
|
54
|
-
## Recorded development trial
|
|
55
|
-
|
|
56
|
-
On September 6, 2026, an Antigravity task through Ennodia found all three current documentation conflicts.
|
|
57
|
-
It also identified the archive as a historical record that did not need changes.
|
|
58
|
-
The primary agent checked each finding against the fixture source.
|
|
59
|
-
This is one successful trial on a small known-answer example, not a general performance result.
|
|
60
|
-
|
|
61
|
-
The fixture includes `recorded-run.json` with the answer, task IDs, timing, and verification notes.
|
|
62
|
-
Local file URL prefixes were normalized for sharing.
|
|
63
|
-
|
|
64
|
-
The video records a later successful repetition through the candidate's MCP server.
|
|
65
|
-
It uses the configured default Antigravity model, with no model override.
|
|
66
|
-
The opt-in script starts one real agent using your configured provider access:
|
|
67
|
-
|
|
68
|
-
```sh
|
|
69
|
-
bun examples/docs-drift/demo.ts --live antigravity
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
Replace `antigravity` with another installed, authenticated harness ID when needed.
|
|
73
|
-
The recording uses the [asciicast format](https://docs.asciinema.org/manual/asciicast/v2/).
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Try a skill separately
|
|
3
|
-
description: Compare two reviews of one function while keeping the main conversation focused.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Try a skill separately
|
|
7
|
-
|
|
8
|
-
A skill can improve a review, add irrelevant work, or make no difference.
|
|
9
|
-
A small separate task gives you evidence before you use its recommendations.
|
|
10
|
-
|
|
11
|
-
The fixture lives in `examples/skill-trial` in the Ennodia checkout.
|
|
12
|
-
It contains a short function and a local contract with deliberate mismatches.
|
|
13
|
-
|
|
14
|
-
## Prepare two comparable attempts
|
|
15
|
-
|
|
16
|
-
1. Select one available agent and model.
|
|
17
|
-
2. Check that the requested skill is installed for that agent.
|
|
18
|
-
3. Give both attempts the same `retry.ts` and `contract.md` files.
|
|
19
|
-
4. Keep the evaluator `check.ts` out of the review materials.
|
|
20
|
-
5. Run the plain review and skill review as separate read-only tasks.
|
|
21
|
-
|
|
22
|
-
```text
|
|
23
|
-
Use Ennodia MCP for two separate read-only reviews of examples/skill-trial/retry.ts.
|
|
24
|
-
Provide contract.md as the source of truth. Use the same agent and model.
|
|
25
|
-
First run: request no additional skill.
|
|
26
|
-
Second run: request the installed source-grounded-audit skill.
|
|
27
|
-
Do not open check.ts until both reviews finish.
|
|
28
|
-
Return each contract mismatch with a concrete failing input.
|
|
29
|
-
Compare useful findings, unsupported claims, and time spent.
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
Your agent can use `ennodia_start_compositional` with one slice per attempt.
|
|
33
|
-
Set `skillIds: []` on the plain slice and `skillIds: ["source-grounded-audit"]` on the skill slice.
|
|
34
|
-
The [skill guide](/docs/guides/agent-skills/) describes installation and explicit selection.
|
|
35
|
-
|
|
36
|
-
A native agent can self-select other available skills.
|
|
37
|
-
An empty requested skill list does not guarantee a skill-free control.
|
|
38
|
-
For strict measurement, use separate controlled skill inventories and record the skills actually loaded.
|
|
39
|
-
|
|
40
|
-
## Validate the findings
|
|
41
|
-
|
|
42
|
-
Run the evaluator after saving both reviews:
|
|
43
|
-
|
|
44
|
-
```sh
|
|
45
|
-
bun examples/skill-trial/check.ts
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
The supplied implementation deliberately fails some cases.
|
|
49
|
-
Use each reported input to check a proposed fix in a disposable copy.
|
|
50
|
-
A useful finding needs to explain a contract mismatch, not just suggest a stylistic change.
|
|
51
|
-
Keep useful partial findings even if the skill adds other irrelevant advice.
|
|
52
|
-
|
|
53
|
-
This fixture supports a repeatable workflow demonstration.
|
|
54
|
-
No quality improvement is claimed for it.
|
|
55
|
-
|
|
56
|
-
## Recorded development trial
|
|
57
|
-
|
|
58
|
-
On September 6, 2026, two Antigravity tasks ran through Ennodia in separate temporary copies.
|
|
59
|
-
The plain review found the six failing evaluator cases and an additional alternative-number-notation case.
|
|
60
|
-
The requested-skill attempt produced no answer because native tool permissions blocked a required read.
|
|
61
|
-
|
|
62
|
-
The agent command exited with code zero despite the permission denial.
|
|
63
|
-
Ennodia initially labeled that task successful. This trial exposed a classification defect that the next release candidate fixes.
|
|
64
|
-
The denied attempt cannot establish the quality of the skill.
|
|
65
|
-
No permission bypass was used to force a successful result.
|
|
66
|
-
|
|
67
|
-
The fixture includes `recorded-trial.json` with both observed outcomes and the diagnostic excerpt.
|
|
68
|
-
Local paths were normalized, and CLI remediation instructions were omitted from the excerpt.
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Benchmarks
|
|
3
|
-
description: Deterministic benchmark snapshots for Ennodia's multi-agent bug-recall suite.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
The first benchmark is `multi-model-bug-recall`: TypeScript review fixtures with
|
|
7
|
-
committed bug oracles. It measures required-finding recall for a condition and
|
|
8
|
-
checks for known false-positive traps.
|
|
9
|
-
|
|
10
|
-
## Current Snapshot
|
|
11
|
-
|
|
12
|
-
Snapshot date: `2026-07-06T14:49:00.060Z`
|
|
13
|
-
|
|
14
|
-
Command:
|
|
15
|
-
|
|
16
|
-
```sh
|
|
17
|
-
bun run bench:bug-recall -- --out /tmp/ennodia-benchmark-snapshot
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
Mode: fixture, using committed reference outputs.
|
|
21
|
-
|
|
22
|
-
The F1 score combines recall and precision. FP means false positive.
|
|
23
|
-
|
|
24
|
-
| Condition | Cases | Recall | Precision | F1 | High recall | FP traps |
|
|
25
|
-
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
|
|
26
|
-
| `claude-code-solo` | 4 | 87.5% | 100% | 93.3% | 100% | 0 |
|
|
27
|
-
| `codex-solo` | 4 | 37.5% | 50% | 42.9% | 75% | 1 |
|
|
28
|
-
| `ennodia-parallel-compare` | 4 | 100% | 100% | 100% | 100% | 0 |
|
|
29
|
-
|
|
30
|
-
Fixture wins: `claude-code-solo` won 3 fixtures, and
|
|
31
|
-
`ennodia-parallel-compare` won 1 fixture. Ennodia's value in this snapshot is
|
|
32
|
-
recall consistency: it recovered every required finding without adding a
|
|
33
|
-
false-positive trap.
|
|
34
|
-
|
|
35
|
-
## How Scoring Works
|
|
36
|
-
|
|
37
|
-
The scorer in `bench/bug-recall/scorer.ts` compares each output with committed
|
|
38
|
-
case oracles:
|
|
39
|
-
|
|
40
|
-
- recall: required findings matched
|
|
41
|
-
- precision: claimed findings that were required
|
|
42
|
-
- high recall: high-severity required findings matched
|
|
43
|
-
- FP traps: known false positives claimed by the output
|
|
44
|
-
|
|
45
|
-
The default benchmark is deterministic. It reads committed fixture responses and
|
|
46
|
-
does not launch child agents:
|
|
47
|
-
|
|
48
|
-
```sh
|
|
49
|
-
bun run bench:bug-recall
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
Live mode starts real local harnesses and varies with installed command-line
|
|
53
|
-
interface (CLI) versions, models, account state, and machine configuration:
|
|
54
|
-
|
|
55
|
-
```sh
|
|
56
|
-
bun run bench:bug-recall:live -- --fixture 001-missing-await
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
## Limitations
|
|
60
|
-
|
|
61
|
-
This is a small TypeScript-focused fixture set. It is recall-oriented, not a
|
|
62
|
-
general software-engineering leaderboard. Live runs are intentionally excluded
|
|
63
|
-
from `bun run verify` because they consume real agent time and depend on local
|
|
64
|
-
setup.
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
# Small Service
|
|
2
|
-
|
|
3
|
-
This is an intentionally inconsistent documentation fixture for Ennodia.
|
|
4
|
-
|
|
5
|
-
The current default port is 3000. Configure another port with `PORT`.
|
|
6
|
-
The readiness response is `{ "status": "ok" }`.
|
|
7
|
-
|
|
8
|
-
The [migration record](./archive/migration.md) describes the previous release.
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import { DEFAULT_PORT, readPort, readiness } from "./config";
|
|
3
|
-
assert.equal(DEFAULT_PORT, 4545);
|
|
4
|
-
assert.equal(readPort({ APP_PORT: "5050" }), 5050);
|
|
5
|
-
assert.equal(readPort({ PORT: "5050" }), 4545);
|
|
6
|
-
assert.deepEqual(readiness(), { ready: true });
|
|
7
|
-
console.log("Current behavior verified. Compare README claims with config.ts; preserve the labeled migration record.");
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export const DEFAULT_PORT = 4545;
|
|
2
|
-
export function readPort(env: Record<string, string | undefined>): number {
|
|
3
|
-
const value = env.APP_PORT;
|
|
4
|
-
return value === undefined ? DEFAULT_PORT : Number(value);
|
|
5
|
-
}
|
|
6
|
-
export function readiness(): { ready: boolean } {
|
|
7
|
-
return { ready: true };
|
|
8
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
-
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
3
|
-
import { resolve } from "node:path";
|
|
4
|
-
|
|
5
|
-
// Opt-in live example. This starts one real agent and uses its configured access.
|
|
6
|
-
if (!process.argv.includes("--live")) {
|
|
7
|
-
console.log("Run: bun examples/docs-drift/demo.ts --live <harness-id>");
|
|
8
|
-
console.log("Example: bun examples/docs-drift/demo.ts --live antigravity");
|
|
9
|
-
process.exit(0);
|
|
10
|
-
}
|
|
11
|
-
const harnessId = process.argv[process.argv.indexOf("--live") + 1];
|
|
12
|
-
if (!harnessId) throw new Error("Select an installed, authenticated harness ID.");
|
|
13
|
-
const root = resolve(import.meta.dir, "../..");
|
|
14
|
-
const client = new Client({ name: "ennodia-docs-demo", version: "1" });
|
|
15
|
-
const transport = new StdioClientTransport({
|
|
16
|
-
command: "bun", args: ["run", "src/cli.ts"], cwd: root, stderr: "pipe",
|
|
17
|
-
});
|
|
18
|
-
async function call(name: string, args: Record<string, unknown>) {
|
|
19
|
-
const result = await client.callTool({ name, arguments: args });
|
|
20
|
-
const text = (result.content as { type: string; text?: string }[])
|
|
21
|
-
.filter((item) => item.type === "text").map((item) => item.text).join("\n");
|
|
22
|
-
if (result.isError) throw new Error(text);
|
|
23
|
-
return JSON.parse(text);
|
|
24
|
-
}
|
|
25
|
-
try {
|
|
26
|
-
console.log("Ennodia live example: find stale documentation");
|
|
27
|
-
console.log(`Agent: ${harnessId}; configured default model; no model override.`);
|
|
28
|
-
console.log("Read-only task: check README against config.ts; preserve labeled history.");
|
|
29
|
-
await client.connect(transport);
|
|
30
|
-
const run = await call("ennodia_run", {
|
|
31
|
-
harnessId, mode: "single", compare: false, cwd: import.meta.dir, timeoutMs: 120000,
|
|
32
|
-
prompt: "Read only README.md, config.ts, and archive/migration.md. Compare current README claims with config.ts. Return each conflict and its correction in plain text, with relative file names only. Explain if the labeled historical migration record needs changes. Do not read other files or edit anything. Keep the response under 180 words.",
|
|
33
|
-
});
|
|
34
|
-
console.log(`Run: ${run.id}\nStatus: ${run.status}`);
|
|
35
|
-
const deadline = Date.now() + 135000;
|
|
36
|
-
for (;;) {
|
|
37
|
-
await Bun.sleep(2000);
|
|
38
|
-
const result = await call("ennodia_get_run", { runId: run.id, includeEvents: false, maxAnswerChars: 5000 });
|
|
39
|
-
if (["succeeded", "failed", "cancelled"].includes(result.status)) {
|
|
40
|
-
console.log(`Status: ${result.status}\nElapsed: ${result.elapsedMs} ms`);
|
|
41
|
-
console.log(result.finalAnswer || JSON.stringify(result.diagnosis ?? "No answer returned."));
|
|
42
|
-
console.log("Check each finding against config.ts before using it.");
|
|
43
|
-
console.log("This is one live attempt, without a speed or cost comparison.");
|
|
44
|
-
if (result.status !== "succeeded") process.exitCode = 1;
|
|
45
|
-
break;
|
|
46
|
-
}
|
|
47
|
-
if (Date.now() > deadline) {
|
|
48
|
-
await call("ennodia_cancel_run", { runId: run.id });
|
|
49
|
-
throw new Error("The bounded demo wait expired.");
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
} finally {
|
|
53
|
-
await client.close();
|
|
54
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"recordedAt": "2026-09-06",
|
|
3
|
-
"kind": "single development trial",
|
|
4
|
-
"harness": "antigravity",
|
|
5
|
-
"model": "Configured default; exact model not established",
|
|
6
|
-
"runId": "d3e36bf1-07dd-4912-af33-b5c904603b44",
|
|
7
|
-
"taskIds": [
|
|
8
|
-
"e822af92-4410-4ed8-9382-f62a6f36a505"
|
|
9
|
-
],
|
|
10
|
-
"status": "succeeded",
|
|
11
|
-
"elapsedMs": 13272,
|
|
12
|
-
"output": "* **Default Port Conflict**: [README.md:L5](../docs-drift/README.md#L5) claims the default port is `3000`, but [config.ts:L1](../docs-drift/config.ts#L1) defines [`DEFAULT_PORT`](../docs-drift/config.ts#L1) as `4545`.\n* **Port Environment Variable Conflict**: [README.md:L5](../docs-drift/README.md#L5) instructs users to configure ports using `PORT`, whereas [`readPort`](../docs-drift/config.ts#L2-L5) in [config.ts:L3](../docs-drift/config.ts#L3) reads `APP_PORT`.\n* **Readiness Response Conflict**: [README.md:L6](../docs-drift/README.md#L6) states the readiness response is `{ \"status\": \"ok\" }`, but [`readiness`](../docs-drift/config.ts#L6-L8) in [config.ts:L6-L7](../docs-drift/config.ts#L6-L7) returns `{ ready: true }`.\n* **Archive Status**: [archive/migration.md](../docs-drift/archive/migration.md#L1-L5) does **not** need changes; as stated in [archive/migration.md:L3-L4](../docs-drift/archive/migration.md#L3-L4), it is explicitly labeled as a historical migration record of the previous release rather than active configuration documentation.",
|
|
13
|
-
"edits": "Local file URL prefixes normalized to fixture-relative paths.",
|
|
14
|
-
"verification": "Primary agent checked all three conflicts and the historical distinction against the fixture.",
|
|
15
|
-
"limitation": "Known-answer fixture. No control run or speed or cost advantage established."
|
|
16
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
# Try a review skill on one small function
|
|
2
|
-
|
|
3
|
-
Compare `retry.ts` with `contract.md`. The function has deliberate defects.
|
|
4
|
-
Run a plain review and a review with a native installed skill in separate tasks.
|
|
5
|
-
Use the same model, files, and request. Save both findings before opening `check.ts`.
|
|
6
|
-
|
|
7
|
-
The evaluator contains the expected cases. Keep it out of the review material.
|
|
8
|
-
This example demonstrates the workflow. It does not establish that a skill improves quality.
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { retryDelaySeconds } from "./retry";
|
|
2
|
-
const cases: [string | null, number][] = [
|
|
3
|
-
[null, 30], ["0", 0], ["12", 12], ["120", 120], ["", 30], [" ", 30],
|
|
4
|
-
["1.5", 30], ["-1", 30], ["121", 30], ["1e2", 30], ["0x10", 30],
|
|
5
|
-
];
|
|
6
|
-
let failures = 0;
|
|
7
|
-
for (const [input, expected] of cases) {
|
|
8
|
-
const actual = retryDelaySeconds(input);
|
|
9
|
-
if (actual !== expected) {
|
|
10
|
-
failures += 1;
|
|
11
|
-
console.log(`${JSON.stringify(input)}: expected ${expected}, received ${actual}`);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
console.log(`${cases.length - failures}/${cases.length} contract cases passed.`);
|
|
15
|
-
process.exitCode = failures ? 1 : 0;
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
# Retry delay contract
|
|
2
|
-
|
|
3
|
-
- A missing value uses 30 seconds.
|
|
4
|
-
- A decimal integer from 0 through 120 specifies the delay in seconds.
|
|
5
|
-
- Zero is valid and means retry immediately.
|
|
6
|
-
- Empty values, whitespace, fractions, negative values, and values over 120 use 30 seconds.
|
|
7
|
-
- The function must not accept numeric notation such as `1e2` or `0x10`.
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"recordedAt": "2026-09-06",
|
|
3
|
-
"kind": "inconclusive native skill trial",
|
|
4
|
-
"harness": "antigravity",
|
|
5
|
-
"model": "Configured default; exact model not established",
|
|
6
|
-
"plain": {
|
|
7
|
-
"taskId": "125ffd40-c224-4615-a441-f31154a26096",
|
|
8
|
-
"status": "succeeded",
|
|
9
|
-
"elapsedMs": 18023,
|
|
10
|
-
"requestedSkills": [],
|
|
11
|
-
"output": "Contract violations identified in [`retryDelaySeconds`](./retry.ts#L2) based on [contract.md](./contract.md):\n\n* **Zero input (`\"0\"`)**: Returns `30` instead of `0` because `Number(\"0\")` evaluates to `0`, which is falsy in `0 || 30`.\n* **Values exceeding upper bound (`\"121\"`)**: Returns `121` instead of `30` because there is no `> 120` boundary check.\n* **Negative values (`\"-1\"`)**: Returns `-1` instead of `30` because negative numbers are truthy and not checked against `< 0`.\n* **Fractions (`\"1.5\"`)**: Returns `1.5` instead of `30` because `Number(\"1.5\")` parses floats without integer validation.\n* **Scientific notation (`\"1e2\"`)**: Returns `100` instead of `30`, directly violating the rule disallowing numeric notation like `1e2`.\n* **Hexadecimal notation (`\"0x10\"`)**: Returns `16` instead of `30`, directly violating the rule disallowing numeric notation like `0x10`.\n* **Binary / octal notation (`\"0b10\"`)**: Returns `2` instead of `30` because `Number()` parses alternative radix notations instead of strictly decimal integers.\n"
|
|
12
|
-
},
|
|
13
|
-
"requestedSkill": {
|
|
14
|
-
"taskId": "233ba69d-b691-4e34-94db-c3fa03a759bb",
|
|
15
|
-
"reportedStatus": "succeeded",
|
|
16
|
-
"observedOutcome": "No answer; required read_file access denied",
|
|
17
|
-
"exitCode": 0,
|
|
18
|
-
"elapsedMs": 17290,
|
|
19
|
-
"requestedSkills": [
|
|
20
|
-
{
|
|
21
|
-
"id": "source-grounded-audit",
|
|
22
|
-
"name": "source-grounded-audit",
|
|
23
|
-
"version": "local",
|
|
24
|
-
"hash": "87366950aa303123d38f7d97cd6cc01a842ca7cc18ffc41f75653bec76fe9cfa",
|
|
25
|
-
"source": "project",
|
|
26
|
-
"harnessIds": [
|
|
27
|
-
"antigravity",
|
|
28
|
-
"claude-code",
|
|
29
|
-
"codex",
|
|
30
|
-
"installable",
|
|
31
|
-
"opencode"
|
|
32
|
-
],
|
|
33
|
-
"native": true
|
|
34
|
-
}
|
|
35
|
-
],
|
|
36
|
-
"stderrExcerpt": "jetski: no output produced — a tool required the \"read_file\" permission that headless mode cannot prompt for, so it was auto-denied.",
|
|
37
|
-
"output": ""
|
|
38
|
-
},
|
|
39
|
-
"edits": "Local file URL prefixes normalized; CLI remediation instructions omitted from the diagnostic excerpt.",
|
|
40
|
-
"verification": "Plain findings checked against the contract and evaluator. This denied attempt cannot measure skill effectiveness.",
|
|
41
|
-
"limitation": "Uncontrolled native skill inventory; loading not verified. The zero-exit false success is fixed in the release candidate."
|
|
42
|
-
}
|