@quolu/lattice 0.12.2 → 0.12.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quolu/lattice",
3
- "version": "0.12.2",
3
+ "version": "0.12.3",
4
4
  "description": "Lattice — phase-aware TODO graph compiler and conflict-aware orchestration runtime",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -252,10 +252,13 @@ export async function startBridgeServer({
252
252
  throw new BridgeConfigError(error?.code === 'EADDRINUSE' ? 'BRIDGE_PORT_UNAVAILABLE' : 'BRIDGE_BIND_FAILED',
253
253
  'bridge listen failed', { ...config.listen }, error);
254
254
  });
255
+ const boundAddress = server.address();
256
+ const actualPort = typeof boundAddress === 'object' && boundAddress !== null
257
+ ? boundAddress.port : config.listen.port;
255
258
  let closed = false;
256
259
  return Object.freeze({
257
260
  address: config.listen.address,
258
- port: config.listen.port,
261
+ port: actualPort,
259
262
  updateConfig(next) {
260
263
  if (next?.enabled !== true || next.listen.address !== config.listen.address
261
264
  || next.listen.port !== config.listen.port) {
package/src/todo-cli.mjs CHANGED
@@ -38,7 +38,7 @@ import {
38
38
  readTodoStore,
39
39
  readTodoStoreStable,
40
40
  rebuildTodoSnapshot,
41
- verifyPhaseTodoRevisionSources,
41
+ verifyEffectivePhaseTodoRevisionSources,
42
42
  verifyTodoRevisionSources,
43
43
  } from './todo-store.mjs';
44
44
  import {
@@ -803,6 +803,7 @@ async function ensureActiveProjectDashboard({ repoRoot, env }) {
803
803
  async function verify({ repoRoot, requestedPlanKey }) {
804
804
  const store = await readTodoStore({ repoRoot });
805
805
  const members = selectMembers(store, requestedPlanKey);
806
+ const verifiedSourceInventories = new Map();
806
807
  for (const member of members) {
807
808
  const unverified = member.tasks.find((task) => task.evidence_unverified);
808
809
  if (unverified !== undefined) {
@@ -816,12 +817,14 @@ async function verify({ repoRoot, requestedPlanKey }) {
816
817
  case 'lattice.todo_revision.v1':
817
818
  case 'lattice.todo_revision.v2':
818
819
  await verifyTodoRevisionSources({ repoRoot, revision: member.revision });
820
+ verifiedSourceInventories.set(member.descriptor.plan_key,
821
+ member.revision.source_inventory);
819
822
  break;
820
823
  case 'lattice.phase_todo_revision.v1':
821
824
  case 'lattice.phase_todo_revision.v2':
822
- break;
823
825
  case 'lattice.phase_todo_revision.v3':
824
- await verifyPhaseTodoRevisionSources({ repoRoot, revision: member.revision });
826
+ verifiedSourceInventories.set(member.descriptor.plan_key,
827
+ await verifyEffectivePhaseTodoRevisionSources({ repoRoot, member }));
825
828
  break;
826
829
  default:
827
830
  throw new TodoStoreError('REVISION_INVALID', 'revision_schema_or_digest_invalid');
@@ -830,6 +833,7 @@ async function verify({ repoRoot, requestedPlanKey }) {
830
833
  }
831
834
  const verifiedMembers = members.map((member) => {
832
835
  const reconciled = member.revision !== null;
836
+ const sourceInventory = verifiedSourceInventories.get(member.descriptor.plan_key) ?? null;
833
837
  const phaseRevision = ['lattice.phase_todo_revision.v1', 'lattice.phase_todo_revision.v2',
834
838
  'lattice.phase_todo_revision.v3']
835
839
  .includes(member.revision?.schema);
@@ -848,15 +852,11 @@ async function verify({ repoRoot, requestedPlanKey }) {
848
852
  : todoLegacyReconciliationDigest({ planDigest: member.plan.plan_digest,
849
853
  journalHeadDigest: member.journal.events.at(-1).event_digest }),
850
854
  source_inventory_count: reconciled
851
- ? phaseRevision && member.revision.schema !== 'lattice.phase_todo_revision.v3' ? 0
852
- : member.revision.source_inventory.active.length
853
- + member.revision.source_inventory.excluded_tombstones.length : null,
855
+ ? sourceInventory.active.length + sourceInventory.excluded_tombstones.length : null,
854
856
  active_task_count: reconciled
855
- ? phaseRevision && member.revision.schema !== 'lattice.phase_todo_revision.v3'
856
- ? 0 : member.revision.source_inventory.active.length : null,
857
+ ? sourceInventory.active.length : null,
857
858
  excluded_tombstone_count: reconciled
858
- ? phaseRevision && member.revision.schema !== 'lattice.phase_todo_revision.v3'
859
- ? 0 : member.revision.source_inventory.excluded_tombstones.length : null,
859
+ ? sourceInventory.excluded_tombstones.length : null,
860
860
  };
861
861
  });
862
862
  const result = {
@@ -2552,6 +2552,21 @@ async function predecessorSourceInventory(repoRoot, previous) {
2552
2552
  return { active: [], excluded_tombstones: [] };
2553
2553
  }
2554
2554
 
2555
+ export async function verifyEffectivePhaseTodoRevisionSources(options = {}) {
2556
+ const repoRoot = path.resolve(options.repoRoot ?? process.cwd());
2557
+ const member = options.member;
2558
+ const revision = member?.revision;
2559
+ if (!validatePhaseTodoRevision(revision)
2560
+ || canonicalizeTodoArtifact(revision.desired_plan)
2561
+ !== canonicalizeTodoArtifact(member?.plan)) {
2562
+ fail('REVISION_INVALID', 'phase_revision_schema_or_digest_invalid');
2563
+ }
2564
+ const inventory = revision.schema === 'lattice.phase_todo_revision.v3'
2565
+ ? revision.source_inventory : await predecessorSourceInventory(repoRoot, member);
2566
+ await verifyRevisionSources(repoRoot, inventory);
2567
+ return inventory;
2568
+ }
2569
+
2555
2570
  function validatePhaseV3SourceInventoryDiff(previousInventory, revision) {
2556
2571
  const desired = revision.source_inventory;
2557
2572
  const previousActive = new Map(previousInventory.active.map((entry) => [entry.task_id, entry]));
@@ -2655,7 +2670,9 @@ async function applyPhaseTodoRevisionV3(options, revision, repoRoot) {
2655
2670
  journalHeadDigest: previous.journal.events.at(-1).event_digest });
2656
2671
  if (revision.reconciliation.predecessor_reconciliation_digest
2657
2672
  !== predecessorReconciliationDigest) fail('STORE_WRITE_CONFLICT', 'stale_predecessor');
2658
- validatePhaseV3SourceInventoryDiff(await predecessorSourceInventory(repoRoot, previous), revision);
2673
+ const previousInventory = await predecessorSourceInventory(repoRoot, previous);
2674
+ await verifyRevisionSources(repoRoot, previousInventory);
2675
+ validatePhaseV3SourceInventoryDiff(previousInventory, revision);
2659
2676
  await rejectCompetingPhaseV3Transaction(repoRoot, revision);
2660
2677
  verifyPlanNarrativeAnchors(repoRoot, revision.desired_plan, previous.plan);
2661
2678
  const stateMigration = stateMigrationFor(previous, revision);