@agentsfleet/orly 0.10.3 → 0.10.5

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/docs/TEMPLATE.md CHANGED
@@ -316,7 +316,19 @@ table. -->
316
316
 
317
317
  **Command source rule:** every S-row Verify command is copied **verbatim from `.oracle/orly.json`** (`conform`, `verify.*`) — the same set `orly gate` runs, so the rubric and the mechanical PR gate grade one boundary. The gate BLOCKs a staged pending/active spec whose rubric omits the declared `conform` or `verify.unit` command; a rubric naming a runner the repository does not declare is wrong by construction. `.oracle/orly.json` still a seed → complete it first (`dispatch/lifecycle.md` §Bootstrap); authoring against an unseeded config is the nondeterminism this rule exists to kill.
318
318
 
319
- **Grading protocol (VERIFY):** run the Verify command verbatim; grade ONLY from its output. Graded = ✅/❌ + the one decisive output line (`342 passed`); long evidence goes to PR Session Notes with a pointer here. **Ship gate:** every row graded, every P0 ✅ → eligible for CHORE(close); any ❌ or empty cell → return to EXECUTE; a P1 ❌ ships only with an Indy-acked deferral quote in Discovery.
319
+ **Grading protocol (VERIFY):** run the Verify command verbatim; grade ONLY from its output. Graded = ✅/❌ + the one decisive output line (`342 passed`); long evidence goes to PR Session Notes with a pointer here. **Ship gate:** every row graded, every P0 ✅ → eligible for CHORE(close); any ❌ or empty cell → return to EXECUTE; a P1 ❌ ships only with an Indy-acked deferral quote in Discovery. A P0 may also be **MOVED** — see below.
320
+
321
+ **A P0 whose SCOPE moves is not a P0 shipped red.** Met and unmet are not the only two states a criterion has, and a gate that pretends otherwise forces an agent to invent a third. One did, twice in a day, before this clause existed.
322
+
323
+ A deferral and a transfer are different claims. A **deferral** leaves work unowned inside a closed spec, which is what the P0 gate exists to prevent — the P1 quote is as far as that goes. A **transfer** moves the criterion whole: its Dimensions, its verification and its rubric row land in a named successor spec that carries them as its own P0. Nothing is less owned afterwards; it is owned somewhere else.
324
+
325
+ Mark such a row `MOVED to M{N}_{NNN} R{n}` and it is not ❌, on three conditions, all of which must hold:
326
+
327
+ 1. The successor spec **exists** and carries the criterion as a rubric row of its own. A successor that does not carry the row is a deferral wearing a new word, and fails the gate as before.
328
+ 2. Both specs record the mapping — the closing spec names where each Dimension went, the successor names what it inherited. One-sided assertion is not a transfer.
329
+ 3. Discovery carries the **owner's verbatim quote** authorising it, in the deferral format. An agent-authored transfer is agent-authored scope reduction.
330
+
331
+ A MOVED row is never rendered ✅. The criterion has not been met; it has changed owner, and the rubric says which.
320
332
 
321
333
  <!-- tpl: The single scoring surface — no other scoreboard. 5–12 rows after
322
334
  pruning: one per Section outcome, failure class, or hygiene gate — never one
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentsfleet/orly",
3
- "version": "0.10.3",
3
+ "version": "0.10.5",
4
4
  "description": "Repository-scoped engineering harness: renders agent rules, materialises the gates that enforce them, and proves the PR boundary \u2014 for any coding agent.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/config.ts CHANGED
@@ -1,8 +1,7 @@
1
- import { createHash } from "node:crypto";
2
1
  import { existsSync, mkdirSync, readdirSync, readFileSync } from "node:fs";
3
2
  import { dirname, extname, join, relative } from "node:path";
4
3
 
5
- import { assertWritableInside, isObject, isString, JsonObject, objectValue, OrlyError, readJsonObject, RulesModel, stringArray } from "./model";
4
+ import { assertWritableInside, hashContent, isObject, isString, JsonObject, objectValue, OrlyError, readJsonObject, RulesModel, stringArray } from "./model";
6
5
  import { UNSCOPED_ENVIRONMENT } from "./git_env";
7
6
  import { validateCommands, validateSurfaces } from "./validation";
8
7
 
@@ -19,7 +18,6 @@ const VERSION_FIELD = "orly_version";
19
18
  const MANAGED_FIELD = "managed";
20
19
  const DIGESTS_FIELD = "digests";
21
20
  const DIGEST_ALGORITHM = "sha256";
22
- const DIGEST_ENCODING = "hex";
23
21
  const COMMANDS_FIELD = "commands";
24
22
  const CONFORM_COMMAND = "conform";
25
23
  const MAKE_COMMAND = "make";
@@ -139,7 +137,7 @@ function readDigests(value: unknown): Record<string, string> {
139
137
  /// and the alternative was a scanner suppression, which is how a real
140
138
  /// credential eventually rides through.
141
139
  export function contentDigest(bytes: Uint8Array): string {
142
- return `${DIGEST_ALGORITHM}:${createHash(DIGEST_ALGORITHM).update(bytes).digest(DIGEST_ENCODING)}`;
140
+ return `${DIGEST_ALGORITHM}:${hashContent(bytes)}`;
143
141
  }
144
142
 
145
143
  // Tolerates the unprefixed spelling 0.10.2 wrote for its one release, so a