@sleepy_panda_srl/portulan 0.1.2 → 0.1.3
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/README.md +2 -2
- package/cli/README.md +69 -2
- package/cli/compile.mjs +555 -37
- package/cli/doctor.mjs +5 -1
- package/cli/drills.mjs +1541 -0
- package/cli/fuzz-shell.mjs +880 -0
- package/cli/gate.mjs +3 -2
- package/cli/goldens.mjs +469 -0
- package/cli/init.mjs +4 -1
- package/cli/mutants.mjs +925 -0
- package/cli/pack-identity.mjs +9 -2
- package/cli/pack-version.mjs +7 -0
- package/cli/recipe-set.mjs +6 -0
- package/cli/release-eval.mjs +1068 -0
- package/cli/review-meter.mjs +741 -0
- package/cli/skill-goldens.mjs +590 -0
- package/cli/stop-gate.mjs +107 -4
- package/cli/telemetry.mjs +1047 -0
- package/cli/version-carriers.mjs +13 -0
- package/core/templates/gate-policy.md +27 -8
- package/evals/README.md +910 -0
- package/evals/releases/0.1.3.json +134 -0
- package/evals/releases/0.1.3.md +64 -0
- package/evals/releases/README.md +32 -0
- package/package.json +7 -2
- package/packs/rituals/checkpoints/README.md +8 -1
- package/packs/rituals/checkpoints/pack.json +1 -1
- package/packs/rituals/checkpoints/skills/pre-commit/SKILL.md +32 -2
- package/spec/slots.md +26 -2
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
{
|
|
2
|
+
"portulan": {
|
|
3
|
+
"releaseEval": "1"
|
|
4
|
+
},
|
|
5
|
+
"version": "0.1.3",
|
|
6
|
+
"captured": "2026-09-16",
|
|
7
|
+
"source": {
|
|
8
|
+
"commit": "fac7b6d36ce3aa53ce93381ef8cce07e503608e4",
|
|
9
|
+
"clean": true
|
|
10
|
+
},
|
|
11
|
+
"host": {
|
|
12
|
+
"node": "v26.8.1",
|
|
13
|
+
"platform": "darwin"
|
|
14
|
+
},
|
|
15
|
+
"recipes": [
|
|
16
|
+
{
|
|
17
|
+
"id": "docs",
|
|
18
|
+
"exit": 0
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": "json",
|
|
22
|
+
"exit": 0
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "doctor",
|
|
26
|
+
"exit": 0
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"id": "tests",
|
|
30
|
+
"exit": 0
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"id": "plugin",
|
|
34
|
+
"exit": 0
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"id": "compile",
|
|
38
|
+
"exit": 0
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"id": "workflow-filters",
|
|
42
|
+
"exit": 0
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"id": "index",
|
|
46
|
+
"exit": 0
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"id": "control-chars",
|
|
50
|
+
"exit": 0
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"id": "rule-carriers",
|
|
54
|
+
"exit": 0
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"id": "pack-version",
|
|
58
|
+
"exit": 0
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"id": "pack-identity",
|
|
62
|
+
"exit": 0
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"id": "payload",
|
|
66
|
+
"exit": 0
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"id": "eval-bundle",
|
|
70
|
+
"exit": 0
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"id": "goldens",
|
|
74
|
+
"exit": 0
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"id": "mutants",
|
|
78
|
+
"exit": 0
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"id": "fuzz-shell",
|
|
82
|
+
"exit": 0
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"id": "version-carriers",
|
|
86
|
+
"exit": 0
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"id": "skill-goldens",
|
|
90
|
+
"exit": 0
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"id": "review-loop",
|
|
94
|
+
"exit": 0
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"id": "telemetry",
|
|
98
|
+
"exit": 0
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"id": "drills",
|
|
102
|
+
"exit": 0
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"id": "ab",
|
|
106
|
+
"exit": 0
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"id": "ab-grade",
|
|
110
|
+
"exit": 0
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"id": "ab-run",
|
|
114
|
+
"exit": 0
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"id": "tools/github:actions-pinned",
|
|
118
|
+
"exit": 0
|
|
119
|
+
}
|
|
120
|
+
],
|
|
121
|
+
"excluded": [
|
|
122
|
+
{
|
|
123
|
+
"id": "release-eval",
|
|
124
|
+
"why": "a capture cannot be accurate about the record it is inside — captured before the record is written it is red for the record's absence, and captured after it is stale the moment the register is rendered. Its verdict for this release is the rail's own run on the pull request carrying this file."
|
|
125
|
+
}
|
|
126
|
+
],
|
|
127
|
+
"abBaseline": {
|
|
128
|
+
"snapshot": "evals/ab/baseline.json",
|
|
129
|
+
"register": "evals/ab/baseline.md",
|
|
130
|
+
"captured": "2026-08-31T09:05:32.699Z",
|
|
131
|
+
"commit": "a642d551eec6c146c67ef0acfe3f8ba535c5ce6e",
|
|
132
|
+
"clean": false
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Eval result — Portulan 0.1.3
|
|
2
|
+
|
|
3
|
+
> **Generated. Do not edit.** Rendered from [`evals/releases/0.1.3.json`](0.1.3.json) by [`cli/release-eval.mjs`](../../cli/release-eval.mjs) and byte-compared by the `release-eval` verify recipe. This is the eval result milestone 8 requires a release to carry — `docs/plan.md`, Protocol → Versioning.
|
|
4
|
+
|
|
5
|
+
## What this release was measured at
|
|
6
|
+
|
|
7
|
+
| | |
|
|
8
|
+
|---|---|
|
|
9
|
+
| Version | `0.1.3` |
|
|
10
|
+
| Captured | 2026-09-16 |
|
|
11
|
+
| Commit | `fac7b6d36ce3aa53ce93381ef8cce07e503608e4` |
|
|
12
|
+
| Tree at capture | clean |
|
|
13
|
+
| Node | `v26.8.1` |
|
|
14
|
+
| Platform | `darwin` |
|
|
15
|
+
|
|
16
|
+
## The rails, and what each returned
|
|
17
|
+
|
|
18
|
+
26 of the 27 recipes this workspace yielded at capture. The set is derived from [`cli/recipe-set.mjs`](../../cli/recipe-set.mjs) and never listed by hand.
|
|
19
|
+
|
|
20
|
+
| Recipe | Verdict |
|
|
21
|
+
|---|---|
|
|
22
|
+
| `docs` | green |
|
|
23
|
+
| `json` | green |
|
|
24
|
+
| `doctor` | green |
|
|
25
|
+
| `tests` | green |
|
|
26
|
+
| `plugin` | green |
|
|
27
|
+
| `compile` | green |
|
|
28
|
+
| `workflow-filters` | green |
|
|
29
|
+
| `index` | green |
|
|
30
|
+
| `control-chars` | green |
|
|
31
|
+
| `rule-carriers` | green |
|
|
32
|
+
| `pack-version` | green |
|
|
33
|
+
| `pack-identity` | green |
|
|
34
|
+
| `payload` | green |
|
|
35
|
+
| `eval-bundle` | green |
|
|
36
|
+
| `goldens` | green |
|
|
37
|
+
| `mutants` | green |
|
|
38
|
+
| `fuzz-shell` | green |
|
|
39
|
+
| `version-carriers` | green |
|
|
40
|
+
| `skill-goldens` | green |
|
|
41
|
+
| `review-loop` | green |
|
|
42
|
+
| `telemetry` | green |
|
|
43
|
+
| `drills` | green |
|
|
44
|
+
| `ab` | green |
|
|
45
|
+
| `ab-grade` | green |
|
|
46
|
+
| `ab-run` | green |
|
|
47
|
+
| `tools/github:actions-pinned` | green |
|
|
48
|
+
|
|
49
|
+
**`release-eval` is excluded**, and the reason is printed rather than the row silently dropped: a capture cannot be accurate about the record it is inside — captured before the record is written it is red for the record's absence, and captured after it is stale the moment the register is rendered. Its verdict for this release is the rail's own run on the pull request carrying this file.
|
|
50
|
+
|
|
51
|
+
## The A/B baseline this release ships against
|
|
52
|
+
|
|
53
|
+
[`evals/ab/baseline.md`](../../evals/ab/baseline.md), rendered from `evals/ab/baseline.json` — captured 2026-08-31T09:05:32.699Z at `a642d551eec6c146c67ef0acfe3f8ba535c5ce6e`, over a tree that was **not clean**.
|
|
54
|
+
|
|
55
|
+
**Its figures are not repeated here.** They have one carrier and this is not it.
|
|
56
|
+
|
|
57
|
+
## What this record does not establish
|
|
58
|
+
|
|
59
|
+
- **A green says this record agrees with its own capture — never that the release is good.** Every line below is what the recipes returned at one commit, and a recipe's own green establishes only what that recipe's documentation says it establishes.
|
|
60
|
+
- **The recipes were not run at the tag.** They ran at `fac7b6d36ce3aa53ce93381ef8cce07e503608e4`, and this record is committed *in* the cut change — so the tagged tree is this commit plus whatever that change still adds after the capture, the record itself at minimum. A record cannot be captured at a commit that does not exist yet, and printing the one it was captured at is the only honest form.
|
|
61
|
+
- **`release-eval` is excluded from the rows above**, because a capture cannot be accurate about the record it is inside. Its verdict for this release is the rail's own run on the pull request that carries this file.
|
|
62
|
+
- **This record measures the Portulan repository's own build**, at the commit named above — never the workspace, project or package this release is installed into. Nothing here has looked at your tree.
|
|
63
|
+
- **The tree was clean at capture**, so the commit named above is what was measured.
|
|
64
|
+
- **The A/B baseline's figures are NOT restated here.** This record names which baseline the release ships against; the figures and everything that may not be concluded from them live in that register alone.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# `evals/releases/`
|
|
2
|
+
|
|
3
|
+
The eval result each release carries, one pair per version — milestone 8's ninth clause. The argument,
|
|
4
|
+
the limits and the two designs a fresh context reversed are in [`../README.md`](../README.md); the
|
|
5
|
+
mechanism is [`../../cli/release-eval.mjs`](../../cli/release-eval.mjs). This file does not restate
|
|
6
|
+
either, because a rule with two carriers is obeyed at the narrower one.
|
|
7
|
+
|
|
8
|
+
- `<version>.json` — the **capture**: the verdict every recipe the workspace yielded returned, at a named
|
|
9
|
+
commit, plus the identity of the A/B baseline that release ships against. Written by
|
|
10
|
+
`node cli/release-eval.mjs --capture`, which runs them. **A hand-edited capture is NOT caught by the
|
|
11
|
+
byte comparison** — that holds the register to the capture, so `--write` re-renders the edit and the
|
|
12
|
+
pair agrees perfectly. What guards a capture is the rail's reading of its *contents*: an exclusion
|
|
13
|
+
list that is anything but the self-exclusion, a recorded non-zero exit, a version not matching the
|
|
14
|
+
release it is filed under, a record for a version never cut or for one the clause does not govern.
|
|
15
|
+
This sentence used to claim the opposite, and a sentence claiming a guard that does not exist is what
|
|
16
|
+
makes the gap it describes look unreachable.
|
|
17
|
+
- `<version>.md` — the **register**, rendered from the capture. Generated; do not edit. `--write`
|
|
18
|
+
re-renders it and the `release-eval` recipe refuses any difference.
|
|
19
|
+
|
|
20
|
+
**Which releases have records is not written here.** `ls` this directory, or run
|
|
21
|
+
`node cli/release-eval.mjs --verify`, which prints the governed set and is the carrier — a sentence
|
|
22
|
+
counting the files beside it would be a hand-maintained figure of a subject that grows once per release,
|
|
23
|
+
which is the defect this repository deletes on sight.
|
|
24
|
+
|
|
25
|
+
**What is fixed, and is the only thing this file states about coverage:** the clause binds *from
|
|
26
|
+
milestone 8* — [`../../docs/plan.md`](../../docs/plan.md), Protocol → Versioning — so `v0.1.0`, `v0.1.1`
|
|
27
|
+
and `v0.1.2` carry none and are never asked to. That is history and cannot change.
|
|
28
|
+
|
|
29
|
+
_(This paragraph read **"This directory is empty of records"** as a standing claim. It would have gone
|
|
30
|
+
false in the very commit that wrote the first record — and, since this directory ships inside the npm
|
|
31
|
+
payload, it would then have been **frozen false beside the record it denied**, in a tarball only another
|
|
32
|
+
release could correct. Caught by a second opinion before the first cut rather than by a reader of it.)_
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sleepy_panda_srl/portulan",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Portulan — an agentic-engineering framework whose product is its files. The CLI wraps the file-based mechanics for hosts beyond Claude Code.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -15,13 +15,18 @@
|
|
|
15
15
|
"core/",
|
|
16
16
|
"spec/",
|
|
17
17
|
"packs/",
|
|
18
|
+
"evals/releases/",
|
|
18
19
|
"README.md",
|
|
19
20
|
"LICENSE",
|
|
20
21
|
"NOTICE",
|
|
21
22
|
"!cli/*.test.mjs",
|
|
22
23
|
"!cli/fixtures",
|
|
23
24
|
"!cli/eval-bundle.mjs",
|
|
24
|
-
"!cli/eval-license.template.md"
|
|
25
|
+
"!cli/eval-license.template.md",
|
|
26
|
+
"!cli/ab.mjs",
|
|
27
|
+
"!cli/ab-run.mjs",
|
|
28
|
+
"!cli/ab-grade.mjs",
|
|
29
|
+
"!cli/payload.mjs"
|
|
25
30
|
],
|
|
26
31
|
"repository": {
|
|
27
32
|
"type": "git",
|
|
@@ -38,7 +38,7 @@ Four verdicts, and which are available depends on the checkpoint.
|
|
|
38
38
|
| Verdict | Means | Available at |
|
|
39
39
|
|---|---|---|
|
|
40
40
|
| **APPROVE** | Proceed as it stands. | session-open · pre-commit |
|
|
41
|
-
| **APPROVE-WITH-ADJUSTMENTS** | Proceed once the numbered adjustments are folded in. Not a soft failure — it is what a working checkpoint usually returns. | session-open · pre-commit |
|
|
41
|
+
| **APPROVE-WITH-ADJUSTMENTS** | Proceed once the numbered adjustments are folded in. Not a soft failure — it is what a working checkpoint usually returns. **At pre-commit the fold itself is then graded** — see that skill. | session-open · pre-commit |
|
|
42
42
|
| **REQUEST-CHANGES** | Does not meet the standard. Name what, and what would meet it. Needs a second pass at the same checkpoint. | all three |
|
|
43
43
|
| **CLOSE** | Every clause of the criterion is demonstrated; the milestone may be marked done. | milestone-close only |
|
|
44
44
|
|
|
@@ -49,6 +49,13 @@ concerns is not a verdict.
|
|
|
49
49
|
proceed on a promise to fold something in, and a close is the one decision with nothing downstream of
|
|
50
50
|
it to catch what was folded in wrongly.
|
|
51
51
|
|
|
52
|
+
**That argument reaches one moment earlier, which is why pre-commit's A-W-A grades its own fold**
|
|
53
|
+
(proposal `0035`, 2026-08-29). Session-open's fold *does* have something downstream — the plan it folds
|
|
54
|
+
into becomes a diff, and pre-commit grades that. **Pre-commit's fold has only the commit.** So the
|
|
55
|
+
verdict that lets work proceed on a promise is, at that moment, a promise nothing checks; measured on a
|
|
56
|
+
change where two of three later review findings were created by the fold and were absent from the graded
|
|
57
|
+
diff.
|
|
58
|
+
|
|
52
59
|
## The fidelity note
|
|
53
60
|
|
|
54
61
|
What a close leaves in the record once the session that wrote it is gone. Four parts, in one clause:
|
|
@@ -65,8 +65,38 @@ whether a status column changed.
|
|
|
65
65
|
## The verdicts this checkpoint may return
|
|
66
66
|
|
|
67
67
|
- **APPROVE** — commit as it stands.
|
|
68
|
-
- **APPROVE-WITH-ADJUSTMENTS** —
|
|
69
|
-
|
|
68
|
+
- **APPROVE-WITH-ADJUSTMENTS** — fold the numbered adjustments, then **grade the fold**: a pass over
|
|
69
|
+
**the fold delta alone**, in a context that did not perform the fold, before the commit.
|
|
70
|
+
- **REQUEST-CHANGES** — the diff does not meet the criterion; it needs work and a second pre-commit pass
|
|
71
|
+
**over the whole diff**.
|
|
72
|
+
|
|
73
|
+
**Grade a fully staged diff.** The whole procedure below is index-shaped, so anything left unstaged was
|
|
74
|
+
not graded and will not appear in the fold delta either — it would pass through both nets. Stage first,
|
|
75
|
+
then grade; this is what practice here already did, and it is stated because the mechanism now depends
|
|
76
|
+
on it rather than merely benefiting from it.
|
|
77
|
+
|
|
78
|
+
**A checkpoint records the tree it graded** — the index it read, as a tree object (`git write-tree`). The
|
|
79
|
+
fold delta is then **`git diff --cached <graded-tree>`**: the recorded tree against the index, which is
|
|
80
|
+
what is about to be committed. Derived, not reconstructed from memory by the person who folded.
|
|
81
|
+
|
|
82
|
+
_Why the fold is graded at all, and why the A-W-A pass is scoped to the delta._ **The tree that ships is
|
|
83
|
+
not the tree that was graded**, and the difference is where a remediation can inject what the checkpoint
|
|
84
|
+
just caught elsewhere. Measured: on one change, folding an adjustment split a table row and left a
|
|
85
|
+
summary count stale three sections above, and folding another **re-measured a question the checkpoint had
|
|
86
|
+
answered correctly** — with a line-based tool against a normalising scanner — and wrote the wrong answer
|
|
87
|
+
over the right one. Neither defect was in the graded diff. A full re-grade after every A-W-A would double
|
|
88
|
+
the cost of the cheapest verdict, which is the ceremony a definition of done should refuse; **the delta is
|
|
89
|
+
the only region a fold-injected defect can be in.**
|
|
90
|
+
|
|
91
|
+
_The delta is **whatever was staged after the grade** — it *should* be the adjustments and nothing else,
|
|
92
|
+
and the mechanism does not guarantee that. **Where it is wider, that is not noise; it is the finding.**
|
|
93
|
+
Post-grade edits nobody proposed are exactly what escapes a checkpoint today, so a pass that sees them is
|
|
94
|
+
worth more than one over a delta that had been trimmed to what the verdict asked for._
|
|
95
|
+
|
|
96
|
+
_What this does not buy, said plainly: whether a fresh context actually read the delta is not checkable —
|
|
97
|
+
a session can claim a pass it did not run. What changes is that the pass now has a **defined subject**,
|
|
98
|
+
derived from the tree rather than recalled by the one who folded._ Provenance: proposal `0035`,
|
|
99
|
+
accepted 2026-08-29.
|
|
70
100
|
|
|
71
101
|
## Why it earns its tokens
|
|
72
102
|
|
package/spec/slots.md
CHANGED
|
@@ -771,8 +771,32 @@ Each of these was a candidate; none is an oversight.
|
|
|
771
771
|
- **A per-host capability matrix.** The vision's `doctor` includes a per-host capability report, but that
|
|
772
772
|
is generated from the host and the compiled gates, not declared by the team. It belongs with the
|
|
773
773
|
enforcement backends in milestone 4.
|
|
774
|
-
- **`evals`.** Milestone 8 owns the eval harness
|
|
775
|
-
|
|
774
|
+
- **`evals`.** Milestone 8 owns the eval harness. **The original reason for deferring is spent, and the
|
|
775
|
+
deferral is re-argued rather than left standing on it.** It read *"a slot pointing at golden tasks
|
|
776
|
+
before any exist would be the emptiest kind of scaffolding"* — and golden tasks exist: the gate corpus
|
|
777
|
+
landed at clause (a) and the core-skill corpus at the row's original first subject. The premise
|
|
778
|
+
expired the day it stopped being true and nothing noticed, which is the shape this file elsewhere
|
|
779
|
+
calls a claim outliving its measurement.
|
|
780
|
+
|
|
781
|
+
**What the deferral now rests on.** A slot is the Workspace Definition's promise that every conforming
|
|
782
|
+
workspace can be asked one question and answer it. `evals/` today holds **two corpora with two
|
|
783
|
+
different oracles** — gates answered by the compiler's own `matchesRule`, skills answered by
|
|
784
|
+
mandate-to-artifact bindings — plus a metering register, and a slot naming that directory would
|
|
785
|
+
promise adopters a shape this repository has not settled for itself. **Revisit when milestone 8
|
|
786
|
+
closes**, by which point the row's nine clauses will have decided what an eval artifact is here.
|
|
787
|
+
Filling it is a schema change, a spec version bump and a migration, so it is not a thing to do in
|
|
788
|
+
passing.
|
|
789
|
+
|
|
790
|
+
**Milestone 8 closed 2026-09-09, so this deferral is now DUE and is not discharged here.** The
|
|
791
|
+
close names it rather than filling it, which is what the sentence above asks for: the drafting is
|
|
792
|
+
commissioned by proposal
|
|
793
|
+
[`../.portulan/proposals/0034-one-spec-bump-carries-both-evals-and-telemetry.md`](../.portulan/proposals/0034-one-spec-bump-carries-both-evals-and-telemetry.md)
|
|
794
|
+
— accepted 2026-08-28 — which carries `evals` **and** `telemetry` in **one** MINOR and settles none of
|
|
795
|
+
the shape: the key names, either slot's structure, and whether a migration is owed are the drafted
|
|
796
|
+
work. Doing that drafting inside the close would be the *"splitting on speculation"* this entry warns
|
|
797
|
+
against, in the change that closed the row it was waiting for. **What the close settled is the
|
|
798
|
+
precondition, not the slot:** `evals/` now holds two corpora, a metering register, an A/B capture and
|
|
799
|
+
a per-release record layer, which is the shape a slot would have to name.
|
|
776
800
|
|
|
777
801
|
## What v2.0 is not
|
|
778
802
|
|