sortie-dogs 0.10.15 → 0.10.18

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 CHANGED
@@ -106,6 +106,37 @@ The pre-v0.10.6 local benchmark condition is closed historical evidence. New
106
106
  development decisions use SWE-bench measurements collected under the frozen
107
107
  contract in [Coding benchmark completion and correctness](docs/benchmark-completion-contract.md).
108
108
 
109
+ ### v0.10.14 SWE-bench Lite dev23 baseline
110
+
111
+ The first complete v0.10.14 baseline was run against all 23 `dev` instances and
112
+ graded with the pinned official harness. It is a fixed candidate baseline, not a
113
+ leaderboard or general success-rate claim.
114
+
115
+ - Candidate: `sortie-dogs@0.10.14`, package SHA-256
116
+ `f2caf67268a5f69b67a252a0d84bfc5ad09db82684aa8c1e0f5c49f8d2986993`.
117
+ - Dataset: `princeton-nlp/SWE-bench_Lite`, revision
118
+ `6ec7bb89b9342f664a54a6e0a6ea6501d3437cc2`, split `dev`.
119
+ - Conditions: pass@1, `attempts_per_instance=1`, `retry_count=0`, per-instance
120
+ inference limit `$1.50`, four independent inference slots, and official
121
+ scoring with `max_workers=1`.
122
+ - Official score: **6/23 (26.1%)**. All 23 rows received an official result.
123
+ - Resolved instances: `marshmallow-code__marshmallow-1343`,
124
+ `marshmallow-code__marshmallow-1359`, `pydicom__pydicom-1256`,
125
+ `pydicom__pydicom-1694`, `pylint-dev__astroid-1333`, and
126
+ `sqlfluff__sqlfluff-1733`.
127
+ - Inference spend: `$15.7542788` under the separate `$50` v0.10.14 campaign.
128
+ - Environment deviations retained in the result: five `pvlib` rows hit the
129
+ NumPy 2.0 removal of `np.Inf`, and `pyvista__pyvista-4315` lacked
130
+ `libGL.so.1`. These rows remain in the denominator and were not silently
131
+ removed.
132
+ - Four non-successful inference terminals (`timeout` or `patch-index-failed`)
133
+ produced empty patches and are counted as unresolved official results.
134
+
135
+ This baseline is the comparison point for any later v0.10.15 candidate. A
136
+ later candidate must use its own package digest and preserve the same dataset,
137
+ official scoring boundary, and declared budget conditions before its score is
138
+ compared with this value.
139
+
109
140
  ## Historical local case study
110
141
 
111
142
  These are completion-filtered local references on one frozen DeepSWE task,
@@ -237,6 +237,8 @@ export declare class OperatorRuntime {
237
237
  propose(root: string, raw: unknown, scopeApprovalTurnID?: string): Promise<OperatorProposal>;
238
238
  private proposeOnce;
239
239
  repair(root: string, draftID: string, patches: unknown): Promise<OperatorProposal>;
240
+ /** A diagnosed spelling repair may not add, widen, or redirect a read grant. */
241
+ private sameReadTarget;
240
242
  private prepareOnce;
241
243
  operatorTask(state: OperatorState): OperatorTask;
242
244
  /** Root-visible handle for the bounded operations delegate; its contract stays host-internal. */
@@ -5,7 +5,7 @@ import { isAbsolute, join, relative, resolve, sep } from "node:path";
5
5
  import { promisify } from "node:util";
6
6
  import { acceptanceContinuityFingerprint, inspectAcceptanceContinuity, normalizeAcceptanceCriteria, ACCEPTANCE_CONTINUITY_EXTENSION, MAX_ACCEPTANCE_CONTINUITY_BYTES, MAX_ACCEPTANCE_CRITERIA } from "./acceptance-continuity.js";
7
7
  import { expandGoalDeclaration, goalDeclarationDefaults, hasGoalCommandAliasConflict } from "./goal-declaration-format.js";
8
- import { normalizeRelativePath } from "./path.js";
8
+ import { normalizeManifestPath, normalizeRelativePath } from "./path.js";
9
9
  import { CONTRACT_TEXT_LIMITS, validateHandoffSchema, validateOperationManifestSchema } from "./validate-schema.js";
10
10
  import { validateManifest } from "./validate-manifest.js";
11
11
  import { profileAgent, RUNTIME_PROFILES } from "./runtime-profile.js";
@@ -574,6 +574,17 @@ export class OperatorRuntime {
574
574
  if (!record(patch) || !exactKeys(patch, ["op", "path", "value"]) || !["replace", "add"].includes(String(patch.op)) || typeof patch.path !== "string" || !Object.hasOwn(patch, "value")) {
575
575
  throw new Error("operator-repair-invalid");
576
576
  }
577
+ const readMatch = /^\/units\/(0|[1-9]\d*)\/read\/(0|[1-9]\d*)$/.exec(patch.path);
578
+ if (readMatch) {
579
+ const unitIndex = Number(readMatch[1]), pathIndex = Number(readMatch[2]);
580
+ const diagnosed = Array.isArray(draft.diagnostics) && draft.diagnostics.some((item) => item.document === "plan" && item.pointer === patch.path && item.code === "operator-scope-invalid");
581
+ if (patch.op !== "replace" || !diagnosed ||
582
+ !await this.sameReadTarget(original.units[unitIndex]?.read?.[pathIndex], patch.value)) {
583
+ throw new Error("operator-repair-path-forbidden");
584
+ }
585
+ draft.plan.units[unitIndex].read[pathIndex] = patch.value;
586
+ continue;
587
+ }
577
588
  if (patch.path === "/git_lifecycle/post_commit_validation") {
578
589
  const finalValidation = original.units.at(-1)?.validation;
579
590
  if (patch.op !== "replace" || !strings(patch.value, true) || !Array.isArray(finalValidation) ||
@@ -625,6 +636,25 @@ export class OperatorRuntime {
625
636
  return this.proposeOnce(root, draft.plan);
626
637
  });
627
638
  }
639
+ /** A diagnosed spelling repair may not add, widen, or redirect a read grant. */
640
+ async sameReadTarget(before, after) {
641
+ if (!text(before) || !text(after))
642
+ return false;
643
+ try {
644
+ if (normalizeRelativePath(after) !== after)
645
+ return false;
646
+ const original = normalizeManifestPath(before);
647
+ if (original.kind === "relative")
648
+ return original.path === after;
649
+ if (!isAbsolute(original.path))
650
+ return false;
651
+ const [left, right] = await Promise.all([realpath(original.path), realpath(resolve(this.projectRoot, after))]);
652
+ return process.platform === "win32" ? left.toLowerCase() === right.toLowerCase() : left === right;
653
+ }
654
+ catch {
655
+ return false;
656
+ }
657
+ }
628
658
  async prepareOnce(root, raw, scopeApprovalTurnID) {
629
659
  const previous = await this.read(root);
630
660
  let immutableReplacement = previous?.phase === "cancelled" &&
@@ -51,6 +51,7 @@ export declare class WorktreeLifecycle {
51
51
  private readonly inFlight;
52
52
  private writeQueue;
53
53
  private transactionQueue;
54
+ private preparationQueue;
54
55
  private transactionLease;
55
56
  private readonly directParentAttestations;
56
57
  private constructor();
@@ -83,6 +84,7 @@ export declare class WorktreeLifecycle {
83
84
  private attestDirectParent;
84
85
  private exactEntry;
85
86
  private createAndLock;
87
+ private createAndLockOnce;
86
88
  private addWorktree;
87
89
  private requireOwnedRecord;
88
90
  private isDirectManagedPath;
@@ -139,6 +139,7 @@ export class WorktreeLifecycle {
139
139
  inFlight = new Set();
140
140
  writeQueue = Promise.resolve();
141
141
  transactionQueue = Promise.resolve();
142
+ preparationQueue = Promise.resolve();
142
143
  transactionLease;
143
144
  directParentAttestations = new Map();
144
145
  constructor(repositoryRoot, worktreeRoot, gitPath, commonGitDir, rootIdentity) {
@@ -831,7 +832,15 @@ export class WorktreeLifecycle {
831
832
  return undefined;
832
833
  return entry;
833
834
  }
834
- async createAndLock(record) {
835
+ createAndLock(record) {
836
+ // Git scans sibling administrative directories while adding and attesting worktrees. A peer's
837
+ // not-yet-written commondir can make Git fail after branch creation. Publish one complete entry
838
+ // at a time under the inventory lease; setup hooks and later worker execution remain concurrent.
839
+ const prepared = this.preparationQueue.then(() => this.createAndLockOnce(record));
840
+ this.preparationQueue = prepared.then(() => undefined, () => undefined);
841
+ return prepared;
842
+ }
843
+ async createAndLockOnce(record) {
835
844
  await this.assertRootIdentity();
836
845
  if (!this.isDirectManagedRecord(record) || await lstat(record.path).catch(() => undefined) !== undefined ||
837
846
  await this.branchExists(record.branch))
@@ -486,7 +486,7 @@ export function createProfiledPlugin(profile, assetVersion) {
486
486
  await registerPreparedGoal(context.sessionID, state);
487
487
  return preparedTask(state);
488
488
  } };
489
- tools[repair] = { description: "Repair a root-owned draft with named fields, git_lifecycle branch/start/message fields, or an already-declared criterion command. Empty patches revalidate the saved draft without resending it. Acceptance, unit count and write scope remain fixed.",
489
+ tools[repair] = { description: "Repair a root-owned draft with named fields, git_lifecycle branch/start/message fields, or an already-declared criterion command. A diagnosed /units/i/read/j scope error may be replaced with a normalized repository-relative spelling of the same resource only: absolute inputs require an existing relative alias whose realpath is identical; read expansion, redirection, whole-array replacement and write-scope repair are forbidden. Empty patches revalidate the saved draft without resending it. Acceptance, unit count and write scope remain fixed.",
490
490
  args: { draft_id: stringSchema, patches_json: stringSchema }, execute: async (args, context) => {
491
491
  await requireRoot(context.sessionID);
492
492
  let patches;
@@ -187,6 +187,10 @@ ${profile.toolPrefix}operator_status to recover the existing draft_id after an i
187
187
  Call ${profile.toolPrefix}repair_operator_plan with that draft_id and patches_json (field operations)
188
188
  to repair only /units/<index>/validation, acceptance_indices, title, or objective. This tool cannot change acceptance,
189
189
  unit count or write scope. Do not regenerate the full plan or collapse units to work around a mapping error.
190
+ A diagnosed operator-scope-invalid at /units/<index>/read/<index> also permits replace with a normalized relative
191
+ spelling of the same resource. An absolute input requires an existing relative alias with identical realpath.
192
+ Repair each diagnosed entry using the newly returned draft_id; never widen or redirect reads, replace the whole
193
+ read array, create an alias through this repair tool, or repair write scope.
190
194
  An empty patches_json array revalidates the saved draft without resending the full plan; prefer this after a runtime repair.
191
195
  The repair tool also permits add/replace of /goal_declaration/criteria/<index>/goal_validation_command (or validation_command)
192
196
  only when the exact command is already declared in the validation list of a unit assigned to that criterion.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sortie-dogs",
3
- "version": "0.10.15",
3
+ "version": "0.10.18",
4
4
  "description": "Bounded agent harness and validated orchestration loop plugin for OpenCode",
5
5
  "keywords": [
6
6
  "opencode",