forgexa-cli 1.77.1__tar.gz → 1.77.2__tar.gz

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.
Files changed (31) hide show
  1. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/PKG-INFO +1 -1
  2. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/forgexa_cli/__init__.py +1 -1
  3. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/forgexa_cli/agent_core.py +78 -14
  4. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/forgexa_cli/daemon.py +9 -3
  5. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/forgexa_cli/runtime_evidence.py +2 -2
  6. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/forgexa_cli.egg-info/PKG-INFO +1 -1
  7. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/pyproject.toml +1 -1
  8. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/README.md +0 -0
  9. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/forgexa_cli/_build_config.py +0 -0
  10. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/forgexa_cli/_local_bind.py +0 -0
  11. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/forgexa_cli/autoupgrade.py +0 -0
  12. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/forgexa_cli/aws_evidence.py +0 -0
  13. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/forgexa_cli/aws_logs_evidence.py +0 -0
  14. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/forgexa_cli/main.py +0 -0
  15. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/forgexa_cli/py.typed +0 -0
  16. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/forgexa_cli/zcode_protocol.py +0 -0
  17. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/forgexa_cli.egg-info/SOURCES.txt +0 -0
  18. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/forgexa_cli.egg-info/dependency_links.txt +0 -0
  19. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/forgexa_cli.egg-info/entry_points.txt +0 -0
  20. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/forgexa_cli.egg-info/requires.txt +0 -0
  21. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/forgexa_cli.egg-info/top_level.txt +0 -0
  22. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/setup.cfg +0 -0
  23. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/tests/test_auth_and_runtime_commands.py +0 -0
  24. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/tests/test_autoupgrade.py +0 -0
  25. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/tests/test_check_command.py +0 -0
  26. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/tests/test_expiry_warnings_and_revoke.py +0 -0
  27. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/tests/test_local_bind_commands.py +0 -0
  28. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/tests/test_runtime_credentials.py +0 -0
  29. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/tests/test_session_credentials.py +0 -0
  30. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/tests/test_silent_install.py +0 -0
  31. {forgexa_cli-1.77.1 → forgexa_cli-1.77.2}/tests/test_upgrade_observability.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: forgexa-cli
3
- Version: 1.77.1
3
+ Version: 1.77.2
4
4
  Summary: Forgexa CLI — command-line client and AI agent runtime for the Forgexa platform
5
5
  Author-email: Jason Sun <dev.winds@gmail.com>
6
6
  License-Expression: MIT
@@ -1,2 +1,2 @@
1
1
  """forgexa-cli — Forgexa command-line client."""
2
- __version__ = "1.77.1"
2
+ __version__ = "1.77.2"
@@ -142,33 +142,97 @@ def redact_implementation_audit(contract: dict, report: object) -> dict | None:
142
142
 
143
143
  if not assess_implementation_audit(contract, report)["report_valid"]:
144
144
  return None
145
+ def redact_check(row: dict) -> dict:
146
+ evidence = []
147
+ for reference in row["evidence"][:20]:
148
+ digest = reference.removeprefix("local-evidence-sha256:")
149
+ evidence.append(reference if digest != reference and len(digest) == 64
150
+ and all(character in "0123456789abcdef" for character in digest)
151
+ else "local-evidence-sha256:" + sha256(reference.encode()).hexdigest())
152
+ check = {"status": row["status"], "evidence": evidence}
153
+ if row["status"] != "covered":
154
+ check.update(description="Local implementation issue remains unresolved; inspect local task evidence.", files=[])
155
+ if row.get("plan_revision"):
156
+ check["plan_revision"] = {
157
+ "reason": "Local evidence conflicts with the approved plan",
158
+ "proposal": "Inspect the source in the requirement workspace and revise analysis and tasks together",
159
+ }
160
+ return check
161
+
145
162
  summary = {"audit_id": contract["audit_id"], "task_checks": [], "acceptance_checks": []}
163
+ coding_ids = {task["id"] for task in contract.get("tasks") or [] if task.get("type") in ("coding", "fix")}
146
164
  for key in ("task_checks", "acceptance_checks"):
147
165
  for row in report[key]:
148
- evidence = []
149
- for reference in row["evidence"][:20]:
150
- digest = reference.removeprefix("local-evidence-sha256:")
151
- evidence.append(reference if digest != reference and len(digest) == 64
152
- and all(character in "0123456789abcdef" for character in digest)
153
- else "local-evidence-sha256:" + sha256(reference.encode()).hexdigest())
154
- check = {"status": row["status"], "evidence": evidence}
166
+ check = redact_check(row)
155
167
  if key == "task_checks":
156
168
  check["task_id"] = row["task_id"]
169
+ if contract.get("version") == 2 and row["task_id"] in coding_ids and isinstance(row.get("implementation_check"), dict):
170
+ check["implementation_check"] = redact_check(row["implementation_check"])
157
171
  else:
158
172
  check.update(index=row["index"], task_ids=row["task_ids"])
159
- if row["status"] != "covered":
160
- check.update(description="Local implementation issue remains unresolved; inspect local task evidence.", files=[])
161
- if row.get("plan_revision"):
162
- check["plan_revision"] = {
163
- "reason": "Local evidence conflicts with the approved plan",
164
- "proposal": "Inspect the source in the requirement workspace and revise analysis and tasks together",
165
- }
166
173
  summary[key].append(check)
167
174
  return summary
168
175
 
169
176
 
177
+ def _assess_implementation_contributions(contract: dict, report: object) -> dict:
178
+ original = assess_implementation_audit({**contract, "version": 1}, report)
179
+ if not original["report_valid"]:
180
+ return original
181
+ task_types = {task["id"]: task.get("type") for task in contract.get("tasks") or []}
182
+ verification_ids = [task_id for task_id, task_type in task_types.items() if task_type in ("testing", "verify")]
183
+ verification_statuses = {row["task_id"]: row["status"] for row in report["task_checks"]}
184
+ checks = []
185
+ issues = []
186
+ pending = []
187
+ for row in report["task_checks"]:
188
+ if not isinstance(row, dict) or task_types.get(row.get("task_id")) not in ("coding", "fix"):
189
+ checks.append(row)
190
+ continue
191
+ implementation = row.get("implementation_check")
192
+ if not isinstance(implementation, dict):
193
+ issues.append(f"Approved coding task '{row.get('task_id')}' requires an evidenced implementation_check")
194
+ checks.append(row)
195
+ continue
196
+ check = {"task_id": row.get("task_id"), **{
197
+ key: implementation[key] for key in ("status", "evidence", "description", "files", "plan_revision")
198
+ if key in implementation
199
+ }}
200
+ if row.get("plan_revision") is not None:
201
+ check["plan_revision"] = row["plan_revision"]
202
+ checks.append(check)
203
+ if implementation.get("status") == "covered" and row.get("status") == "gap":
204
+ issues.append(f"Approved task '{row.get('task_id')}' reports a gap despite claiming implementation coverage")
205
+ if implementation.get("status") == "covered" and row.get("status") in ("blocked", "unverified"):
206
+ if not verification_ids:
207
+ issues.append("Runtime acceptance is pending but the approved plan has no verification task")
208
+ pending.extend({
209
+ "task_id": task_id, "status": row.get("status"),
210
+ "description": row.get("description") or "Runtime acceptance remains pending",
211
+ "files": [], "evidence": row.get("evidence") or [],
212
+ } for task_id in verification_ids if verification_statuses.get(task_id) != "covered")
213
+ result = assess_implementation_audit({**contract, "version": 1}, {**report, "task_checks": checks})
214
+ result["report"] = report
215
+ result["issues"].extend(issues)
216
+ result["report_valid"] = not result["issues"]
217
+ result["node_complete"] = result["node_complete"] and not issues
218
+ result["verification_pending"] = sorted({item["task_id"] for item in pending})
219
+ result["findings"].extend(pending)
220
+ for request in original["revision_requests"]:
221
+ if request not in result["revision_requests"]:
222
+ result["revision_requests"].append(request)
223
+ result["followup_task_ids"] = sorted({finding["task_id"] for finding in result["findings"]})
224
+ if issues or pending:
225
+ result["status"] = "incomplete"
226
+ if result["report_valid"] and result["revision_requests"]:
227
+ result["status"] = "plan_revision_required"
228
+ result["node_complete"] = False
229
+ return result
230
+
231
+
170
232
  def assess_implementation_audit(contract: dict, report: object) -> dict:
171
233
  """Validate implementation coverage independently of later runtime acceptance."""
234
+ if contract.get("version") == 2:
235
+ return _assess_implementation_contributions(contract, report)
172
236
  issues: list[str] = []
173
237
  findings: list[dict] = []
174
238
  result = {
@@ -1234,7 +1234,7 @@ except (ImportError, ModuleNotFoundError):
1234
1234
  # DAEMON_VERSION is the protocol/logic version of the daemon code.
1235
1235
  # Kept in sync with pyproject.toml version via bump-version.sh.
1236
1236
  # CLIENT_TYPE identifies which packaging/distribution this daemon runs in.
1237
- DAEMON_VERSION = "1.77.1"
1237
+ DAEMON_VERSION = "1.77.2"
1238
1238
 
1239
1239
 
1240
1240
  def _detect_client_type() -> str:
@@ -9915,6 +9915,7 @@ class ServerConnection:
9915
9915
  "acceptance_verification": {
9916
9916
  "protocol_version": runtime_evidence.DEFERRED_ACCEPTANCE_VERIFICATION_PROTOCOL_VERSION,
9917
9917
  },
9918
+ "implementation_audit": {"protocol_version": 2},
9918
9919
  "task_attachment_staging": {"protocol_version": 1, "runtime_proxy": True, "image_agents": ["claude"]},
9919
9920
  },
9920
9921
  "server_url": self.server_url,
@@ -10338,6 +10339,7 @@ class ServerConnection:
10338
10339
  "acceptance_verification": {
10339
10340
  "protocol_version": runtime_evidence.DEFERRED_ACCEPTANCE_VERIFICATION_PROTOCOL_VERSION,
10340
10341
  },
10342
+ "implementation_audit": {"protocol_version": 2},
10341
10343
  "local_evidence": {"protocol_version": 1, "structured_summary": True},
10342
10344
  "task_attachment_staging": {"protocol_version": 1, "runtime_proxy": True, "image_agents": ["claude"]},
10343
10345
  },
@@ -13875,7 +13877,11 @@ class RuntimeDaemon:
13875
13877
  issues: list[str] = []
13876
13878
  node_type = task.node_type
13877
13879
  input_data = task.input_data or {}
13878
- if agent_core.is_implementation_testing_task(node_type, input_data):
13880
+ fix_context = input_data.get("fix_context")
13881
+ if node_type == "testing" or (
13882
+ node_type == "fix" and input_data.get("task") == "phase_remediation_fix"
13883
+ and isinstance(fix_context, dict) and fix_context.get("failed_node_type") == "testing"
13884
+ ):
13879
13885
  node_type = "testing"
13880
13886
  req_type = input_data.get("requirement_type", "feature")
13881
13887
  verification_work_item = bool(input_data.get("verification_work_item"))
@@ -13897,7 +13903,7 @@ class RuntimeDaemon:
13897
13903
  result.error = "Approved analysis and task plan require revision before implementation can continue"
13898
13904
  issues.append(result.error)
13899
13905
  elif not audit_result["report_valid"] or not audit_result["node_complete"]:
13900
- issues.extend(audit_result["issues"] or audit_result["blocking_reasons"] or [
13906
+ issues.extend(audit_result["issues"] or audit_result.get("blocking_reasons") or [
13901
13907
  "The selected approved task still has implementation gaps",
13902
13908
  ])
13903
13909
 
@@ -15,7 +15,7 @@ from pathlib import Path
15
15
  from typing import Any
16
16
 
17
17
  RUNTIME_EVIDENCE_PLAN_VERSION = 1
18
- DEFERRED_ACCEPTANCE_VERIFICATION_PROTOCOL_VERSION = 2
18
+ DEFERRED_ACCEPTANCE_VERIFICATION_PROTOCOL_VERSION = 3
19
19
  TEST_COVERAGE_CHECK_KIND = "test_coverage"
20
20
  STATIC_CHECK_KIND = "static_check"
21
21
  TYPE_CHECK_KIND = "type_check"
@@ -804,7 +804,7 @@ def validate_deferred_acceptance_criteria(
804
804
  or policy.get("enforcement") != "enforce"
805
805
  or not isinstance(e2e_policy, dict)
806
806
  or type(contract.get("version")) is not int
807
- or contract["version"] not in (1, DEFERRED_ACCEPTANCE_VERIFICATION_PROTOCOL_VERSION)
807
+ or contract["version"] not in (1, 2, DEFERRED_ACCEPTANCE_VERIFICATION_PROTOCOL_VERSION)
808
808
  or contract.get("execution_phase") != "verification_final"
809
809
  or not isinstance(snapshot.get("fingerprint"), str)
810
810
  or contract.get("qa_test_level_policy_fingerprint") != snapshot["fingerprint"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: forgexa-cli
3
- Version: 1.77.1
3
+ Version: 1.77.2
4
4
  Summary: Forgexa CLI — command-line client and AI agent runtime for the Forgexa platform
5
5
  Author-email: Jason Sun <dev.winds@gmail.com>
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "forgexa-cli"
3
- version = "1.77.1"
3
+ version = "1.77.2"
4
4
  description = "Forgexa CLI — command-line client and AI agent runtime for the Forgexa platform"
5
5
  requires-python = ">=3.9"
6
6
  license = "MIT"
File without changes
File without changes