qualia-framework 3.3.1 → 3.3.2
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/bin/state.js +9 -3
- package/package.json +1 -1
- package/tests/runner.js +19 -2
package/bin/state.js
CHANGED
|
@@ -393,9 +393,15 @@ function cmdTransition(opts) {
|
|
|
393
393
|
{ ...opts, phase }
|
|
394
394
|
);
|
|
395
395
|
if (!check.ok) {
|
|
396
|
-
// Force
|
|
397
|
-
//
|
|
398
|
-
|
|
396
|
+
// Force bypasses status-ordering errors AND plan-content errors. The use case
|
|
397
|
+
// is retroactive bookkeeping: a phase was built without /qualia-plan and the
|
|
398
|
+
// user is catching STATE.md up to reality. `--force` never bypasses MISSING_FILE
|
|
399
|
+
// or MISSING_ARG — those would leave the state machine pointing at nothing.
|
|
400
|
+
const forceableErrors = [
|
|
401
|
+
"PRECONDITION_FAILED",
|
|
402
|
+
"GAP_CYCLE_LIMIT",
|
|
403
|
+
"INVALID_PLAN",
|
|
404
|
+
];
|
|
399
405
|
if (opts.force && forceableErrors.includes(check.error)) {
|
|
400
406
|
console.error(`WARNING: Forcing transition despite: ${check.message}`);
|
|
401
407
|
} else {
|
package/package.json
CHANGED
package/tests/runner.js
CHANGED
|
@@ -774,14 +774,31 @@ waves: 1
|
|
|
774
774
|
}
|
|
775
775
|
});
|
|
776
776
|
|
|
777
|
-
it("--force
|
|
777
|
+
it("--force bypasses INVALID_PLAN (retroactive bookkeeping)", () => {
|
|
778
|
+
// Use case: a phase was built without /qualia-plan and the user is
|
|
779
|
+
// catching STATE.md up to reality. The plan file exists as documentation
|
|
780
|
+
// but lacks `**Done when:**` markers — that should not block --force.
|
|
778
781
|
const tmpDir = makeProject();
|
|
779
782
|
try {
|
|
780
783
|
fs.writeFileSync(path.join(tmpDir, ".planning", "phase-1-plan.md"), "# No tasks here");
|
|
784
|
+
const r = runState(["transition", "--to", "planned", "--force"], tmpDir);
|
|
785
|
+
assert.equal(r.status, 0);
|
|
786
|
+
const out = JSON.parse(r.stdout);
|
|
787
|
+
assert.equal(out.ok, true);
|
|
788
|
+
assert.equal(out.status, "planned");
|
|
789
|
+
} finally {
|
|
790
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
791
|
+
}
|
|
792
|
+
});
|
|
793
|
+
|
|
794
|
+
it("--force still rejects MISSING_FILE", () => {
|
|
795
|
+
// Sanity: --force unblocks plan-content errors but not "no plan at all".
|
|
796
|
+
const tmpDir = makeProject();
|
|
797
|
+
try {
|
|
781
798
|
const r = runState(["transition", "--to", "planned", "--force"], tmpDir);
|
|
782
799
|
assert.equal(r.status, 1);
|
|
783
800
|
const out = JSON.parse(r.stdout);
|
|
784
|
-
assert.equal(out.error, "
|
|
801
|
+
assert.equal(out.error, "MISSING_FILE");
|
|
785
802
|
} finally {
|
|
786
803
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
787
804
|
}
|