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 CHANGED
@@ -393,9 +393,15 @@ function cmdTransition(opts) {
393
393
  { ...opts, phase }
394
394
  );
395
395
  if (!check.ok) {
396
- // Force only bypasses status-ordering errors (PRECONDITION_FAILED, GAP_CYCLE_LIMIT).
397
- // Never bypass MISSING_FILE, MISSING_ARG, INVALID_PLAN those cause broken state.
398
- const forceableErrors = ["PRECONDITION_FAILED", "GAP_CYCLE_LIMIT"];
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qualia-framework",
3
- "version": "3.3.1",
3
+ "version": "3.3.2",
4
4
  "description": "Claude Code workflow framework by Qualia Solutions. Plan, build, verify, ship.",
5
5
  "bin": {
6
6
  "qualia-framework": "./bin/cli.js"
package/tests/runner.js CHANGED
@@ -774,14 +774,31 @@ waves: 1
774
774
  }
775
775
  });
776
776
 
777
- it("--force does NOT bypass INVALID_PLAN", () => {
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, "INVALID_PLAN");
801
+ assert.equal(out.error, "MISSING_FILE");
785
802
  } finally {
786
803
  fs.rmSync(tmpDir, { recursive: true, force: true });
787
804
  }