@pennixrv/trellis 0.7.1-beta.10 → 0.7.1-beta.11

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.
@@ -0,0 +1,9 @@
1
+ {
2
+ "version": "0.7.1-beta.11",
3
+ "description": "收敛 handoff ownership 为一次性交接",
4
+ "breaking": false,
5
+ "recommendMigrate": false,
6
+ "changelog": "移除消费后 ownership reconcile 入口;consume 成功后 ownership generation 固定,普通任务修改、提交、阶段推进和交付收尾不再改写交接归属。保留 sealed-source 在 claim 前的 continuity digest 恢复核对,以及只读 transfer status --include-current。",
7
+ "migrations": [],
8
+ "notes": "No migration required. Existing consumed ownership records remain readable and are not rewritten."
9
+ }
@@ -5,6 +5,6 @@
5
5
  "recommendMigrate": true,
6
6
  "changelog": "任务保留 planning、in_progress、completed、cancelled 四个状态;目录随原生生命周期操作同步迁移。完成任务按月份保存,取消任务单独保存。任务发现、父子关系、上下文、状态栏、初始化和平台模板统一使用新布局;旧布局需要显式迁移。",
7
7
  "migrations": [],
8
- "migrationGuide": "## 任务目录迁移\n\n先运行 trellis update --migrate 更新脚本与工作流,并审查自定义文件冲突。更新模板不会自动移动任务。随后运行 python3 .trellis/scripts/task.py migrate-layout 预览,确认后运行 python3 .trellis/scripts/task.py migrate-layout --apply。planning、in_progress、cancelled 任务进入同名子目录;completed 任务进入 completed/YYYY-MM,旧 archive 的月份保持不变。task.json.status 是唯一状态事实,迁移不授予历史任务实施权限,也不重写历史正文或交接包。\n\n无效 JSON、重名、未关闭的委派资源、待交接所有权或不安全路径会阻止整个迁移。先处理明确的输入问题,再重新预览。发生中断时运行 python3 .trellis/scripts/task.py migrate-layout --recover,核验后重新预览;不要手工移动目录或删除事务记录。迁移会同步改写机器引用和当前会话指针;若连续性摘要变化,按原生 phase 接纳和 transfer reconcile 流程重新收敛当前所有权,保留历史交接摘要。",
8
+ "migrationGuide": "## 任务目录迁移\n\n先运行 trellis update --migrate 更新脚本与工作流,并审查自定义文件冲突。更新模板不会自动移动任务。随后运行 python3 .trellis/scripts/task.py migrate-layout 预览,确认后运行 python3 .trellis/scripts/task.py migrate-layout --apply。planning、in_progress、cancelled 任务进入同名子目录;completed 任务进入 completed/YYYY-MM,旧 archive 的月份保持不变。task.json.status 是唯一状态事实,迁移不授予历史任务实施权限,也不重写历史正文或交接包。\n\n无效 JSON、重名、未关闭的委派资源、待交接所有权或不安全路径会阻止整个迁移。先处理明确的输入问题,再重新预览。发生中断时运行 python3 .trellis/scripts/task.py migrate-layout --recover,核验后重新预览;不要手工移动目录或删除事务记录。迁移会同步改写机器引用和当前会话指针;若连续性摘要变化,按原生 phase 接纳和 capture 重新核对当前事实。handoff ownership 在 consume 后完成转移,后续普通任务修改不更新交接代次;需要查看现场时使用只读 transfer status --include-current,保留历史交接摘要。",
9
9
  "aiInstructions": "完整检查迁移预览、四种状态及月份分布、任务数量、父子关系和当前会话路径。只修复有证据的历史输入错误,不把 archive 中未完成任务伪造为 completed。使用原生生命周期入口完成或取消任务,不手写运行状态。保护项目配置、历史正文、二进制附件和不可变交接包。迁移后再次预览应为空,并运行 task.py list、current、phase show 和项目检查验证现场。"
10
10
  }
@@ -33,7 +33,7 @@ The read-only trellis task progress command summarizes planning, in_progress, co
33
33
 
34
34
  旧平铺目录和 `archive/YYYY-MM` 只能作为显式迁移输入。先运行 `task.py migrate-layout` 预览,再使用 `--apply`;已完成 archive 任务保留原月份,非终态任务按真实状态归位,不伪造完成。`--recover` 恢复未完成事务。重复名称、无效 JSON、符号链接、未知执行资源或交接所有权冲突会阻止迁移;不跳过记录。
35
35
 
36
- 移动同步 JSON/JSONL 机器引用、会话指针及 runtime 哈希索引;终态操作在同一事务中清除本任务 runtime。历史正文和正式交接包保留。内容绑定的接受证据或 continuity digest 失效后,通过原生重新接受、capture、目标会话 reconcile 核对,不静默重授历史授权。文档中的 `<task-dir>` 指包含状态及必要月份的真实任务相对路径。
36
+ 移动同步 JSON/JSONL 机器引用、会话指针及 runtime 哈希索引;终态操作在同一事务中清除本任务 runtime。历史正文和正式交接包保留。内容绑定的接受证据或 continuity digest 失效后,通过原生重新接受和 capture 核对,不静默重授历史授权。handoff ownership 在 `consume` 后完成转移;后续普通任务修改不更新交接代次,需要查看现场时使用只读 `transfer status --include-current`。文档中的 `<task-dir>` 指包含状态及必要月份的真实任务相对路径。
37
37
 
38
38
  ## Context manifests
39
39
 
@@ -385,17 +385,13 @@ def transfer_task_ownership(args: argparse.Namespace) -> int:
385
385
  if not PACKAGE_DIGEST_RE.fullmatch(args.expected_continuity_digest):
386
386
  raise ContinuityError("TASK_TRANSFER_INVALID_INPUT", "expected continuity digest must be a SHA-256 digest")
387
387
  if args.expected_continuity_digest != current_digest:
388
- raise ContinuityError("TASK_TRANSFER_STALE_CONTINUITY", "current task projection differs from the explicitly reconciled snapshot")
388
+ raise ContinuityError("TASK_TRANSFER_STALE_CONTINUITY", "current task projection differs from the explicitly checked snapshot")
389
389
  # Recovery acknowledges a live target snapshot without rebasing the source package.
390
- reconciled_claim = (
390
+ recovered_claim = (
391
391
  operation == "claim" and record["status"] == "sealed"
392
392
  and args.expected_continuity_digest == current_digest
393
393
  )
394
- reconciled_target = (
395
- operation == "reconcile" and record["status"] == "consumed"
396
- and args.expected_continuity_digest == current_digest
397
- )
398
- if operation != "release" and current_digest != record.get("target_continuity_digest", record["continuity_digest"]) and not (reconciled_claim or reconciled_target):
394
+ if operation != "release" and current_digest != record.get("target_continuity_digest", record["continuity_digest"]) and not recovered_claim:
399
395
  raise ContinuityError("TASK_TRANSFER_STALE_CONTINUITY", "task continuity changed during ownership transfer")
400
396
  if operation != "release" and _route_snapshot(data) != record["route"]:
401
397
  raise ContinuityError("TASK_TRANSFER_STALE_ROUTE", "task phase, route, input, or implementation authorization changed")
@@ -403,13 +399,10 @@ def transfer_task_ownership(args: argparse.Namespace) -> int:
403
399
  if operation in {"seal", "retire"}:
404
400
  if context_key != record["source_session_id"] or current_path not in {record["task_path"], None}:
405
401
  raise ContinuityError("TASK_TRANSFER_WITHHELD", "source session no longer owns the current task")
406
- elif operation in {"claim", "consume", "reconcile"}:
402
+ elif operation in {"claim", "consume"}:
407
403
  if context_key == record["source_session_id"]:
408
404
  raise ContinuityError("TASK_TRANSFER_WITHHELD", "target must be a different direct session")
409
- if operation == "reconcile":
410
- if not reconciled_target or context_key != record["target_session_id"] or current_path != record["task_path"]:
411
- raise ContinuityError("TASK_TRANSFER_WITHHELD", "only the consumed target may reconcile its explicitly pinned projection")
412
- elif operation == "release":
405
+ if operation == "release":
413
406
  if record["status"] not in {"quiescing", "sealed", "recovery_required"} or record["target_session_id"] is not None:
414
407
  raise ContinuityError("TASK_TRANSFER_INVALID_TRANSITION", "ownership can be released only before target claim")
415
408
  if context_key != record["source_session_id"] or current_path not in {None, record["task_path"]}:
@@ -422,9 +415,7 @@ def transfer_task_ownership(args: argparse.Namespace) -> int:
422
415
  path.unlink(missing_ok=True)
423
416
  print(json.dumps({"status": "released", "generation": record["generation"], "task_id": task_id}, ensure_ascii=False, sort_keys=True))
424
417
  return 0
425
- if operation == "reconcile":
426
- record.update({"target_continuity_digest": current_digest, "generation": record["generation"] + 1})
427
- elif operation == "seal" and record["status"] == "quiescing":
418
+ if operation == "seal" and record["status"] == "quiescing":
428
419
  record.update({"status": "sealed", "generation": record["generation"] + 1})
429
420
  elif operation == "retire" and record["status"] in {"sealed", "retiring", "recovery_required"}:
430
421
  if record["status"] == "sealed":
@@ -440,14 +431,14 @@ def transfer_task_ownership(args: argparse.Namespace) -> int:
440
431
  write_json(path, record)
441
432
  raise ContinuityError("TASK_TRANSFER_RECOVERY_REQUIRED", "source pointer remains after retirement")
442
433
  record["status"] = "ready"
443
- elif operation == "claim" and (record["status"] in {"ready", "claiming", "recovery_required", "claimed"} or reconciled_claim):
434
+ elif operation == "claim" and (record["status"] in {"ready", "claiming", "recovery_required", "claimed"} or recovered_claim):
444
435
  if record["status"] in {"claiming", "recovery_required"} and record["target_session_id"] != context_key:
445
436
  raise ContinuityError("TASK_TRANSFER_WITHHELD", "only the recorded target session can recover a claim")
446
437
  if current_path not in {None, record["task_path"]}:
447
438
  raise ContinuityError("TASK_TRANSFER_WITHHELD", "target session already has a current task")
448
439
  if record["status"] in {"ready", "sealed"}:
449
440
  record.update({"status": "claiming", "generation": record["generation"] + 1, "target_session_id": context_key})
450
- if reconciled_claim:
441
+ if recovered_claim:
451
442
  record["target_continuity_digest"] = current_digest
452
443
  if not write_json(path, record):
453
444
  raise ContinuityError("TASK_TRANSFER_WRITE_FAILED", "could not record target claim")
@@ -497,12 +488,12 @@ def add_continuity_commands(subparsers) -> None:
497
488
  capture.add_argument("--expected-source-digest", required=True, help="Current captured digest, or absent")
498
489
 
499
490
  transfer = subparsers.add_parser("transfer", help="Transfer task ownership between direct sessions")
500
- transfer.add_argument("transfer_action", choices=("status", "quiesce", "seal", "retire", "claim", "consume", "release", "reconcile"))
491
+ transfer.add_argument("transfer_action", choices=("status", "quiesce", "seal", "retire", "claim", "consume", "release"))
501
492
  transfer.add_argument("--task-id", required=True)
502
493
  transfer.add_argument("--task-path", required=True)
503
494
  transfer.add_argument("--package-id", required=True)
504
495
  transfer.add_argument("--package-digest", required=True)
505
- transfer.add_argument("--expected-continuity-digest", help="Expected live projection; required for sealed-source claim or consumed-target reconciliation")
496
+ transfer.add_argument("--expected-continuity-digest", help="Expected live projection for sealed-source claim recovery")
506
497
  transfer.add_argument("--expected-generation", type=int)
507
498
  transfer.add_argument("--include-current", action="store_true", help="Include the live task projection and its digest in transfer status")
508
499
  transfer.add_argument("--explicit-user-request", action="store_true")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pennixrv/trellis",
3
- "version": "0.7.1-beta.10",
3
+ "version": "0.7.1-beta.11",
4
4
  "description": "AI capabilities grow like ivy — Trellis provides the structure to guide them along a disciplined path",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -34,7 +34,7 @@
34
34
  "inquirer": "^9.3.7",
35
35
  "undici": "^6.21.0",
36
36
  "zod": "^4.4.2",
37
- "@pennixrv/trellis-core": "0.7.1-beta.10"
37
+ "@pennixrv/trellis-core": "0.7.1-beta.11"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@eslint/js": "^9.18.0",