feature-factory 0.10.2 → 0.10.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.
@@ -106,7 +106,9 @@ Use exactly these field names and exactly this `status` vocabulary. The orchestr
106
106
  block to `factory observe --claim`, which compares each field against what it observes itself and
107
107
  records every disagreement as a review finding. `completed` is the word the evidence uses; any
108
108
  other spelling reads as a disagreement about status and blocks your own slice. `files_changed`
109
- must list every path, and `tests.exit` must be the real exit code — a claimed zero against an
109
+ must list every path changed since the slice's `base_ref`, not since your last attempt — on a retry
110
+ the observer diffs the whole slice, because that is what merges, and a list of only this attempt's
111
+ edits is a disagreement. `tests.exit` must be the real exit code — a claimed zero against an
110
112
  observed failure is the single most important disagreement this mechanism catches.
111
113
 
112
114
  If the brief is wrong or impossible as written (e.g. the entity doesn't support it), stop, set `status: blocked` with the reason in `blockers`, and report the conflict — do not silently improvise a different design.
@@ -114,7 +114,9 @@ Use exactly these field names and exactly this `status` vocabulary. The orchestr
114
114
  block to `factory observe --claim`, which compares each field against what it observes itself and
115
115
  records every disagreement as a review finding. `completed` is the word the evidence uses; any
116
116
  other spelling reads as a disagreement about status and blocks your own slice. `files_changed`
117
- must list every path, and `tests.exit` must be the real exit code — a claimed zero against an
117
+ must list every path changed since the slice's `base_ref`, not since your last attempt — on a retry
118
+ the observer diffs the whole slice, because that is what merges, and a list of only this attempt's
119
+ edits is a disagreement. `tests.exit` must be the real exit code — a claimed zero against an
118
120
  observed failure is the single most important disagreement this mechanism catches.
119
121
 
120
122
  If the design brief and the brief conflict, or a token/component the design needs doesn't exist, stop, set `status: blocked` with the reason in `blockers`, and report — don't hardcode around it.
package/observe/index.js CHANGED
@@ -123,10 +123,16 @@ export function runTests(worktree, command, { runner = spawnSync, skipReason = n
123
123
  return { cmd: shellCommand ? command : command.join(" "), exit, observed: exit !== null, skipped_reason: null };
124
124
  }
125
125
 
126
- // Readiness requires completed, clean, changed, observed-diff evidence and tests
127
- // observed passing or ratified as explicitly skipped with a reason.
126
+ // Readiness requires completed, clean, changed, observed-diff evidence, no disagreement between
127
+ // the builder's claim and the observation, and tests observed passing or ratified as explicitly
128
+ // skipped with a reason.
128
129
  export function deriveReviewReady(evidence) {
129
130
  if (evidence.status !== "completed") return false;
131
+ // Enforcement (false green): a claim that disagrees with observation is itself the finding. It
132
+ // lives here, not beside the writer, because `readEvidence` recomputes readiness from this
133
+ // function alone; with the term only at write time, every mismatched record read back as
134
+ // tampered and wedged its slice where `slice blocked` could never record it.
135
+ if (evidence.claim_reconciliation?.mismatches?.length > 0) return false;
130
136
  // A tree with uncommitted changes cannot produce evidence about the commit it
131
137
  // claims, whatever the tests said.
132
138
  if (evidence.worktree_clean !== true) return false;
@@ -250,11 +256,8 @@ export function buildEvidence({ subject, runId, attempt, branch, baseRef, worktr
250
256
  review_ready: false,
251
257
  claim_reconciliation: { claimed: false, mismatches: [] },
252
258
  };
253
- evidence.review_ready = deriveReviewReady(evidence);
254
259
  evidence.claim_reconciliation = reconcileClaim(claim, evidence);
255
- // A claim that disagrees with what we observed cannot be review-ready: the
256
- // disagreement is itself the finding.
257
- if (evidence.claim_reconciliation.mismatches.length > 0) evidence.review_ready = false;
260
+ evidence.review_ready = deriveReviewReady(evidence);
258
261
  return evidence;
259
262
  }
260
263
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "feature-factory",
3
- "version": "0.10.2",
3
+ "version": "0.10.3",
4
4
  "description": "Durable, observed control plane for /feature runs. Host-agnostic: no opencode dependency.",
5
5
  "type": "module",
6
6
  "license": "MIT",