project-loop-harness 0.2.4__tar.gz → 0.3.1__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.
- {project_loop_harness-0.2.4/src/project_loop_harness.egg-info → project_loop_harness-0.3.1}/PKG-INFO +28 -1
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/README.md +27 -0
- project_loop_harness-0.3.1/agent-tasks/0108-target-bound-code-context-receipts.md +152 -0
- project_loop_harness-0.3.1/agent-tasks/0113-evidence-links-table.md +118 -0
- project_loop_harness-0.3.1/agent-tasks/0114-source-hash-drift.md +78 -0
- project_loop_harness-0.3.1/agent-tasks/0115-context-pack-contract-fixtures.md +72 -0
- project_loop_harness-0.3.1/agent-tasks/0116-receipt-link-agreement-validation.md +163 -0
- project_loop_harness-0.3.1/agent-tasks/0117-markdown-target-refresh-command.md +76 -0
- project_loop_harness-0.3.1/agent-tasks/0118-canonical-target-bound-handoff-docs.md +64 -0
- project_loop_harness-0.3.1/agent-tasks/0119-context-check-preflight.md +145 -0
- project_loop_harness-0.3.1/agent-tasks/0120-pcl-finish-terminal-closeout.md +140 -0
- project_loop_harness-0.3.1/agent-tasks/0121-human-gate-japanese-guidance.md +61 -0
- project_loop_harness-0.3.1/agent-tasks/0122-feature-coverage-noop.md +80 -0
- project_loop_harness-0.3.1/agent-tasks/README.md +55 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/adoption-guide.md +19 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/code-context.md +54 -6
- project_loop_harness-0.3.1/docs/context-check.md +74 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/context-pack.md +46 -18
- project_loop_harness-0.3.1/docs/finish.md +75 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/growth-plan-v0.2.4-v0.5.md +43 -1
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/release-notes/v0.2.4.md +12 -2
- project_loop_harness-0.3.1/docs/release-notes/v0.3.0.md +90 -0
- project_loop_harness-0.3.1/docs/release-notes/v0.3.1.md +89 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/pyproject.toml +1 -1
- project_loop_harness-0.3.1/src/pcl/__init__.py +1 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/cli.py +150 -1
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/code_context/impact.py +94 -1
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/code_context/receipts.py +40 -2
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/commands.py +308 -78
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/context.py +473 -18
- project_loop_harness-0.3.1/src/pcl/context_binding.py +20 -0
- project_loop_harness-0.3.1/src/pcl/db/migrations/007_evidence_links.sql +19 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/db.py +1 -1
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/evidence.py +86 -1
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/locales.py +56 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/validators.py +97 -1
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/workflows.py +37 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1/src/project_loop_harness.egg-info}/PKG-INFO +28 -1
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/project_loop_harness.egg-info/SOURCES.txt +20 -0
- project_loop_harness-0.3.1/tests/fixtures/context_pack_code_context_contract_v0.json +441 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_cli_init.py +7 -4
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_code_index.py +187 -1
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_context.py +585 -15
- project_loop_harness-0.3.1/tests/test_context_check.py +517 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_evidence_add.py +120 -0
- project_loop_harness-0.3.1/tests/test_finish.py +222 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_migrations.py +179 -50
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_next_actions.py +62 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_validation.py +193 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_workflows.py +96 -0
- project_loop_harness-0.2.4/agent-tasks/README.md +0 -35
- project_loop_harness-0.2.4/src/pcl/__init__.py +0 -1
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/LICENSE +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/MANIFEST.in +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/Makefile +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0001-hardening-cli.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0002-db-migrations.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0003-workflow-runner.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0004-dashboard-renderer.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0005-agent-integration.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0006-codex-plugin.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0007-mcp-server.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0008-loop-lifecycle.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0009-defect-lifecycle.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0010-reporting-evidence.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0011-validation-invariants.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0012-audit-log-integrity.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0013-validation-diagnostics.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0014-escalation-lifecycle.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0015-decision-lifecycle.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0016-escalation-decision-linkage.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0017-next-action-guided-loop.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0018-readme-golden-path.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0019-recovery-playbook.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0020-example-project-refresh.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0021-agent-adapter-contract.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0022-agent-output-validation.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0023-codex-exec-adapter-hardening.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0024-claude-manual-adapter-hardening.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0025-generic-shell-adapter.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0026-agent-job-evidence-ingestion.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0027-dashboard-data-contract.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0028-dashboard-evidence-navigation.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0029-dashboard-risk-and-blockers.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0030-distribution-readiness.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0031-workflow-proposal-mode.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0032-workflow-proposal-review.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0033-workflow-verifier.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0034-limited-execution-sandbox.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0035-automatic-workflow-executor.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0036-executor-dogfood-workflow.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0037-executor-retry-resume.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0038-story-test-lifecycle.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0039-workflow-yaml-rule-expressions.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0040-test-case-evidence-validation.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0041-feature-inspection-commands.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0042-report-coverage-context.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0043-feature-report.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0044-complete-csv-export.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0045-filtered-job-inspection.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0046-feature-status-lifecycle.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0047-feature-coverage-next-action.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0048-migration-status-command.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0049-render-json-artifact-paths.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0050-codex-plugin-package-inventory.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0051-mcp-render-artifact-paths.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0052-lifecycle-failure-job-cleanup.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0053-prompt-job-json-handoff.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0054-human-queue-linkage-cli.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0055-workflow-proposal-list-filter.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0056-sandbox-noop-execution-guard.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0057-executor-no-executable-step-guard.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0058-dogfood-usability-hardening.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0059-checkpoint-review-guidance.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0060-pypi-trusted-publishing.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0061-context-pack-v1.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0062-task-backlog-entity.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0063-structured-verification-rubric.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0064-task-loop-integration.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0065-dashboard-human-decisions.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0066-agent-registry-lease.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0067-context-pack-improvements.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0068-trust-hardening.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0069-explainable-code-context-v0.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0070-human-decision-cockpit.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0071-dogfood-impact-precision.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0072-sensitive-omission.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0073-code-context-module-split.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0074-search-snapshot-consistency.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0075-diff-source-modes.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0076-schema-version-integrity.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0077-index-output-budget-and-impact-noise.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0078-context-pack-code-context-bridge.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0079-receipt-human-summary.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0080-retrieval-eval-gate.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0081-diff-modes-completion.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0082-receipt-relevance-and-age.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0083-required-section-invariant.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0084-source-commands-honesty.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0085-distribution-source-completeness.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0086-command-surface-alignment.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0087-verification-suggestion-ids.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0088-verification-feedback.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0089-dogfood-fixture-propose.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0090-eval-baseline-record-compare.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0091-refresh-command-scope-fidelity.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0092-idempotent-status-transitions.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0093-evidence-add-command.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0094-job-completion-evidence.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0095-supporting-evidence-health.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0096-evidence-add-path-guards.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0097-evidence-durability-design.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0098-field-feedback-next-weight-and-run-report-scope.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0099-evidence-copy-mode.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0100-evidence-task-linking.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0101-evidence-id-allocation-race.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0102-source-drift-health-warning.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0103-security-policy-v02x.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0104-python-ci-matrix.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0105-evidence-copy-observability.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0106-release-checklist.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/agent-tasks/0107-agent-tasks-backlog-index.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/adr/0001-hybrid-state.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/adr/0002-cli-is-the-runtime.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/adr/0003-static-workflows-before-dynamic-workflows.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/agent-adapter-contract.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/agent-output-template.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/agent-roles.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/architecture.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/dashboard-data-contract.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/dashboard-design.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/data-model.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/distribution.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/evidence-durability-design.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/evidence-entry-paths-design.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/feedback/2026-07-06-ax1-moc1-agent-feedback.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/golden-path.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/implementation-plan.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/master-trace-handoff.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/plh_v0_1_11_review_agenda.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/plh_v0_1_12_review_agenda.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/pypi-publishing.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/recovery-playbook.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/release-checklist.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/safety-permissions.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/v0.2.0-plan.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/verification-feedback-design.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/verification-feedback.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/verification-rubric.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/docs/workflow-contract.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/scripts/run_advisory_retrieval_eval.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/scripts/verify_sdist_contracts.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/setup.cfg +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/__main__.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/agents.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/checkpoints.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/code_context/__init__.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/code_context/diff.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/code_context/eval.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/code_context/scan.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/code_context/search.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/code_context/store.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/code_context/summary.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/code_context/symbols.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/code_context/test_hints.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/code_index.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/db/migrations/001_initial.sql +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/db/migrations/002_tasks.sql +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/db/migrations/003_agent_registry.sql +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/db/migrations/004_code_index.sql +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/db/migrations/005_verification_feedback.sql +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/db/migrations/006_evidence_task_link.sql +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/db/schema.sql +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/decisions.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/dispatch.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/errors.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/escalations.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/events.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/exporters.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/guards.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/ids.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/init_project.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/lifecycle.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/links.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/mcp_server.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/migrations.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/paths.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/receipt_show.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/registry.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/renderer.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/reports.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/resources.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/rubric.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/stories.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/tasks.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/templates/dashboard/dashboard.html +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/templates/project/AGENTS.block.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/templates/project/CLAUDE.block.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/templates/project/gitignore.fragment +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/templates/project/pcl.yaml +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/templates/skills/project-control-loop/SKILL.md +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/templates/workflows/defect_repair.yaml +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/templates/workflows/executor_smoke.yaml +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/templates/workflows/feature_coverage.yaml +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/templates/workflows/regression_loop.yaml +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/timeutil.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/token_estimation.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/update_check.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/verification_feedback.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/verifications.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/workflow_executor.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/workflow_proposal_validation.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/workflow_proposals.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/workflow_sandbox.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/workflow_verifier.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/pcl/workflow_yaml.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/project_loop_harness.egg-info/dependency_links.txt +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/project_loop_harness.egg-info/entry_points.txt +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/project_loop_harness.egg-info/requires.txt +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/src/project_loop_harness.egg-info/top_level.txt +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/fixtures/code_context_summary_v0.json +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/fixtures/context_receipt_v0.json +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/fixtures/context_receipt_v0_legacy_string_suggestions.json +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/fixtures/retrieval_adversarial_v0.json +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/fixtures/retrieval_real_history_v0.json +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/fixtures/retrieval_v0.json +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_advisory_retrieval_eval_script.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_agent_adapter_contract.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_agent_output_validation.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_agents.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_audit_log_integrity.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_checkpoints.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_claude_manual_adapter.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_code_context_summary.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_codex_exec_adapter.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_codex_plugin.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_dashboard.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_dashboard_data_contract.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_decisions.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_defects.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_dispatch.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_distribution.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_escalations.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_examples.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_features.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_generic_shell_adapter.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_golden_path.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_lifecycle.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_mcp_server.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_pypi_publishing.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_receipt_show.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_recovery_playbook.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_registry.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_reports.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_rubric.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_stories.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_tasks.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_update_check.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_validation_diagnostics.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_verification_feedback.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_workflow_executor.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_workflow_proposals.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_workflow_sandbox.py +0 -0
- {project_loop_harness-0.2.4 → project_loop_harness-0.3.1}/tests/test_workflow_verifier.py +0 -0
{project_loop_harness-0.2.4/src/project_loop_harness.egg-info → project_loop_harness-0.3.1}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: project-loop-harness
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Local control plane for agentic project development loops
|
|
5
5
|
Author: Project Loop Harness Contributors
|
|
6
6
|
License: MIT
|
|
@@ -269,6 +269,33 @@ evidence. Receipts use the fields `included_candidate_context`, `omitted`, and
|
|
|
269
269
|
See [docs/code-context.md](docs/code-context.md) for the index, impact,
|
|
270
270
|
receipt, and retrieval-eval contracts.
|
|
271
271
|
|
|
272
|
+
### Target-bound agent handoff (v0.3)
|
|
273
|
+
|
|
274
|
+
To hand another agent auditable, target-scoped code context, bind a receipt to
|
|
275
|
+
the task or job, then require that binding when you build the pack:
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
pcl index build --json
|
|
279
|
+
pcl impact --diff --for-task T-0001 --json
|
|
280
|
+
pcl context pack --task T-0001 --include-code-context --require-bound-receipt --json
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Use the `--for-job` / `--job` forms for an agent-job handoff:
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
pcl impact --diff --for-job J-0001 --json
|
|
287
|
+
pcl context pack --job J-0001 --include-code-context --require-bound-receipt --json
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
`pcl impact --diff --for-task` (or `--for-job`) records a caller-asserted binding
|
|
291
|
+
between the diff-based receipt and the target. With `--require-bound-receipt` the
|
|
292
|
+
pack fails with `context_pack_bound_receipt_required` instead of silently using an
|
|
293
|
+
unrelated latest receipt, so a worker never receives another task's context under
|
|
294
|
+
a target-bound label. The binding records that a receipt was created for the
|
|
295
|
+
target (`binding_strength: caller_asserted`) — not that the receipt is sufficient
|
|
296
|
+
or that any agent read it. Because the receipt comes from a diff, this is a
|
|
297
|
+
review/continuation handoff and presumes a change already exists for the target.
|
|
298
|
+
|
|
272
299
|
## Guided Next Actions
|
|
273
300
|
|
|
274
301
|
`pcl next` is the loop router. The JSON output keeps the original fields and adds stable guidance fields:
|
|
@@ -237,6 +237,33 @@ evidence. Receipts use the fields `included_candidate_context`, `omitted`, and
|
|
|
237
237
|
See [docs/code-context.md](docs/code-context.md) for the index, impact,
|
|
238
238
|
receipt, and retrieval-eval contracts.
|
|
239
239
|
|
|
240
|
+
### Target-bound agent handoff (v0.3)
|
|
241
|
+
|
|
242
|
+
To hand another agent auditable, target-scoped code context, bind a receipt to
|
|
243
|
+
the task or job, then require that binding when you build the pack:
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
pcl index build --json
|
|
247
|
+
pcl impact --diff --for-task T-0001 --json
|
|
248
|
+
pcl context pack --task T-0001 --include-code-context --require-bound-receipt --json
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Use the `--for-job` / `--job` forms for an agent-job handoff:
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
pcl impact --diff --for-job J-0001 --json
|
|
255
|
+
pcl context pack --job J-0001 --include-code-context --require-bound-receipt --json
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
`pcl impact --diff --for-task` (or `--for-job`) records a caller-asserted binding
|
|
259
|
+
between the diff-based receipt and the target. With `--require-bound-receipt` the
|
|
260
|
+
pack fails with `context_pack_bound_receipt_required` instead of silently using an
|
|
261
|
+
unrelated latest receipt, so a worker never receives another task's context under
|
|
262
|
+
a target-bound label. The binding records that a receipt was created for the
|
|
263
|
+
target (`binding_strength: caller_asserted`) — not that the receipt is sufficient
|
|
264
|
+
or that any agent read it. Because the receipt comes from a diff, this is a
|
|
265
|
+
review/continuation handoff and presumes a change already exists for the target.
|
|
266
|
+
|
|
240
267
|
## Guided Next Actions
|
|
241
268
|
|
|
242
269
|
`pcl next` is the loop router. The JSON output keeps the original fields and adds stable guidance fields:
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# 0108: Target-bound code context receipts
|
|
2
|
+
|
|
3
|
+
Milestone: v0.3.0 Target-Bound Context
|
|
4
|
+
Priority: P1
|
|
5
|
+
Area: code-context/context-pack
|
|
6
|
+
Origin: docs/growth-plan-v0.2.4-v0.5.md v0.3.0; docs/project-loop-harness-v0.2.3-third-party-review.md P2-3
|
|
7
|
+
Depends on: 0113 (evidence_links table, migration 007) — merge first.
|
|
8
|
+
|
|
9
|
+
> **Revision 2026-07-08 (坂本承認):** the original no-migration invariant is
|
|
10
|
+
> **retracted**. Target binding is now persisted as a queryable `evidence_links`
|
|
11
|
+
> row (`link_role="code_context"`, from 0113) **and** embedded in the receipt
|
|
12
|
+
> artifact; receipt selection is a SQL query, not an artifact scan. This unblocks
|
|
13
|
+
> `pcl context check` (v0.3.1) and v0.4 `bound_receipt_coverage` without a second
|
|
14
|
+
> migration later.
|
|
15
|
+
|
|
16
|
+
## Problem
|
|
17
|
+
|
|
18
|
+
`pcl context pack --include-code-context` currently reads the latest
|
|
19
|
+
`context_receipt` evidence row. The pack tells the reader that this is
|
|
20
|
+
`scope: "unscoped_latest"` with `binding_strength: "none"`, which is honest,
|
|
21
|
+
but it still risks handing a worker a receipt from an unrelated task or job.
|
|
22
|
+
|
|
23
|
+
The existing docs reserve `scope: "target_bound"` and
|
|
24
|
+
`binding_strength: "caller_asserted"`, but there is no command path that
|
|
25
|
+
creates or requires such a receipt. v0.3.0 turns that reserved contract into a
|
|
26
|
+
narrow, explicit handoff workflow, backed by queryable link state.
|
|
27
|
+
|
|
28
|
+
## Scope
|
|
29
|
+
|
|
30
|
+
1. Extend `pcl impact --diff` with explicit target flags:
|
|
31
|
+
- `--for-task T-XXXX`
|
|
32
|
+
- `--for-job J-XXXX`
|
|
33
|
+
Exactly zero or one target flag is allowed. Existing diff mode flags
|
|
34
|
+
(`--base`, `--staged`, `--unstaged`, `--include-untracked`,
|
|
35
|
+
`--all-changes`, and provided diff input) keep their current semantics.
|
|
36
|
+
2. Validate the named target before writing a receipt. Missing or malformed
|
|
37
|
+
target IDs must fail with a typed error and must not create evidence or an
|
|
38
|
+
`evidence_links` row.
|
|
39
|
+
3. When a target flag is present, record the binding in **two** places, in the
|
|
40
|
+
same transaction that writes the receipt evidence:
|
|
41
|
+
- An `evidence_links` row (0113 helper): `(evidence_id=<receipt>,
|
|
42
|
+
target_type, target_id, link_role="code_context", created_at)`, where
|
|
43
|
+
`target_type` is `task` or `agent_job`.
|
|
44
|
+
- Target binding metadata inside the `impact/v0` response and the
|
|
45
|
+
`context-receipt/v0` artifact so the receipt is self-describing:
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"target_binding": {
|
|
49
|
+
"target_type": "task",
|
|
50
|
+
"target_id": "T-0001",
|
|
51
|
+
"binding_strength": "caller_asserted",
|
|
52
|
+
"source": "impact_flag"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
For job targets, use `target_type: "agent_job"`. The link row and the
|
|
57
|
+
artifact `target_binding` must agree.
|
|
58
|
+
4. Update context-pack receipt selection when `--include-code-context` is used.
|
|
59
|
+
Selection is a **query on `evidence_links`** (0113 helper), not an artifact
|
|
60
|
+
scan:
|
|
61
|
+
- For a task pack, prefer the newest receipt evidence with a matching
|
|
62
|
+
`evidence_links` row `(target_type="task", target_id=<task>,
|
|
63
|
+
link_role="code_context")`.
|
|
64
|
+
- For a job pack, prefer the newest matching
|
|
65
|
+
`(target_type="agent_job", target_id=<job>, link_role="code_context")`.
|
|
66
|
+
- If no matching bound receipt exists, preserve the current unscoped latest
|
|
67
|
+
fallback unless the caller requires a bound receipt.
|
|
68
|
+
5. Add `pcl context pack --require-bound-receipt`, valid only with
|
|
69
|
+
`--include-code-context`. When no matching bound receipt exists, fail with a
|
|
70
|
+
typed error `context_pack_bound_receipt_required` and include a
|
|
71
|
+
target-specific refresh suggestion:
|
|
72
|
+
- `pcl impact --diff --for-task T-XXXX --json`
|
|
73
|
+
- `pcl impact --diff --for-job J-XXXX --json`
|
|
74
|
+
6. Update `code_context.relevance` in the embedded summary:
|
|
75
|
+
- Matching bound receipt: `scope: "target_bound"`,
|
|
76
|
+
`binding_strength: "caller_asserted"`, plus `target_type` and
|
|
77
|
+
`target_id`.
|
|
78
|
+
- Unbound fallback: keep `scope: "unscoped_latest"` and
|
|
79
|
+
`binding_strength: "none"` with an explicit warning.
|
|
80
|
+
- Missing receipt: keep `scope: "missing_receipt"` and
|
|
81
|
+
`binding_strength: "none"`.
|
|
82
|
+
7. Update docs and CLI help for `docs/code-context.md`,
|
|
83
|
+
`docs/context-pack.md`, and relevant tests.
|
|
84
|
+
|
|
85
|
+
## Invariants (what to protect, on the normal paths)
|
|
86
|
+
|
|
87
|
+
- Binding is recorded in lockstep: when a target flag is given, the receipt
|
|
88
|
+
evidence row, its `evidence_links` `code_context` row, and the artifact
|
|
89
|
+
`target_binding` are written in one transaction and must agree. Never write
|
|
90
|
+
the link row without the receipt, or an artifact `target_binding` without the
|
|
91
|
+
link row.
|
|
92
|
+
- Binding is a **caller assertion**, not PLH proof that the receipt is
|
|
93
|
+
semantically relevant. Use claims-not-facts vocabulary; do not add fields such
|
|
94
|
+
as `safe_to_continue`, `verified_relevant`, or `agent_read`.
|
|
95
|
+
- Extend `impact/v0`, `context-receipt/v0`, and `context-pack/v1` **additively**
|
|
96
|
+
via the `code-context-summary/v0` insulation layer (0078). The pack embeds the
|
|
97
|
+
summary and `receipt_ref` (evidence_id / receipt_path) only — never the full
|
|
98
|
+
receipt body or copied evidence contents.
|
|
99
|
+
- `pcl context pack` remains read-only: it must not run `pcl index build`,
|
|
100
|
+
`pcl impact`, Git commands, tests, or any artifact-generating command. It
|
|
101
|
+
reads `evidence_links` and evidence rows only.
|
|
102
|
+
- `source_commands` remain read-only re-fetch commands. Artifact-generating
|
|
103
|
+
commands (`pcl impact …`) appear only under `suggested_refresh_commands`.
|
|
104
|
+
- Existing unscoped latest behavior remains available when
|
|
105
|
+
`--require-bound-receipt` is absent.
|
|
106
|
+
- Deterministic generated artifacts stay deterministic; timestamped facts remain
|
|
107
|
+
in receipt/evidence payloads where timestamps already exist.
|
|
108
|
+
|
|
109
|
+
## Non-scope
|
|
110
|
+
|
|
111
|
+
- Semantic or embedding-based relevance proof.
|
|
112
|
+
- Automatic target inference from changed files, branches, or task text.
|
|
113
|
+
- `pcl context pack --receipt ...` manual receipt selection.
|
|
114
|
+
- `pcl receipt list` / `pcl evidence link` CLI verbs.
|
|
115
|
+
- Dashboard redesign or MCP surface changes.
|
|
116
|
+
- Hosted code analysis, cloud sync, telemetry, or external LLM calls.
|
|
117
|
+
- `pcl context check` preflight (deferred to v0.3.1).
|
|
118
|
+
|
|
119
|
+
## Acceptance
|
|
120
|
+
|
|
121
|
+
- `pcl impact --diff --for-task T-0001 --json` writes a receipt with
|
|
122
|
+
`target_binding.target_type == "task"` and `target_id == "T-0001"`, and an
|
|
123
|
+
`evidence_links` row `(target_type="task", target_id="T-0001",
|
|
124
|
+
link_role="code_context")`.
|
|
125
|
+
- `pcl impact --diff --for-job J-0001 --json` writes a receipt with
|
|
126
|
+
`target_binding.target_type == "agent_job"` and `target_id == "J-0001"`, and
|
|
127
|
+
the matching `code_context` link row.
|
|
128
|
+
- Invalid target IDs and mutually exclusive target flags fail with typed errors
|
|
129
|
+
before any evidence or link row is created.
|
|
130
|
+
- `pcl context pack --task T-0001 --include-code-context --json` chooses the
|
|
131
|
+
newest matching task-bound receipt over a newer unbound receipt, via the
|
|
132
|
+
`evidence_links` query.
|
|
133
|
+
- `pcl context pack --job J-0001 --include-code-context --json` chooses the
|
|
134
|
+
newest matching job-bound receipt over a newer unbound receipt.
|
|
135
|
+
- Without a matching bound receipt and without `--require-bound-receipt`,
|
|
136
|
+
context pack still succeeds with the existing unscoped latest warning and a
|
|
137
|
+
target-specific suggested refresh command.
|
|
138
|
+
- With `--require-bound-receipt` and no matching bound receipt, context pack
|
|
139
|
+
fails with `context_pack_bound_receipt_required` and does not silently fall
|
|
140
|
+
back to unscoped latest.
|
|
141
|
+
- `source_commands` for code-context packs still contain only read-only
|
|
142
|
+
commands; `pcl impact` appears only under `suggested_refresh_commands`.
|
|
143
|
+
- Full `pytest` green.
|
|
144
|
+
- Live smoke in a scratch project:
|
|
145
|
+
1. `pcl init`
|
|
146
|
+
2. create a goal and task
|
|
147
|
+
3. `pcl index build --json`
|
|
148
|
+
4. make a small tracked change
|
|
149
|
+
5. `pcl impact --diff --for-task T-0001 --json`
|
|
150
|
+
6. `pcl context pack --task T-0001 --include-code-context --require-bound-receipt --json`
|
|
151
|
+
7. `pcl validate --strict --json`
|
|
152
|
+
8. `pcl render --json`
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# 0113: Generic evidence links table (migration 007)
|
|
2
|
+
|
|
3
|
+
Milestone: v0.3.0 Target-Bound Context
|
|
4
|
+
Priority: P1
|
|
5
|
+
Area: schema/evidence
|
|
6
|
+
Origin: docs/growth-plan-v0.2.4-v0.5.md v0.3.0; third-party review 議題1 — migration
|
|
7
|
+
approved and 0108 no-migration invariant retracted (Sakamoto approved 2026-07-08).
|
|
8
|
+
|
|
9
|
+
## Problem
|
|
10
|
+
|
|
11
|
+
Evidence-to-target linkage is currently a single `evidence.linked_task_id`
|
|
12
|
+
column (migration 006), which can only express "supporting evidence for a
|
|
13
|
+
task". v0.3.0 introduces a second link role — a code-context receipt bound
|
|
14
|
+
to a task or job (0108) — and v0.3.2 will add master-trace / intent-index
|
|
15
|
+
roles. A single typed column cannot express a role, and adding one column per
|
|
16
|
+
target type (`linked_job_id`, `linked_goal_id`, and so on) sprawls.
|
|
17
|
+
|
|
18
|
+
Introduce a generic, queryable `evidence_links` table so target-bound receipt
|
|
19
|
+
selection (0108), `pcl context check` (v0.3.1), and v0.4 coverage KPIs become
|
|
20
|
+
SQL queries rather than artifact scans. This is a control-plane primitive, not
|
|
21
|
+
a per-feature column.
|
|
22
|
+
|
|
23
|
+
## Scope
|
|
24
|
+
|
|
25
|
+
1. Add migration `007_evidence_links.sql`:
|
|
26
|
+
```sql
|
|
27
|
+
PRAGMA foreign_keys = ON;
|
|
28
|
+
|
|
29
|
+
CREATE TABLE IF NOT EXISTS evidence_links (
|
|
30
|
+
evidence_id TEXT NOT NULL REFERENCES evidence(id),
|
|
31
|
+
target_type TEXT NOT NULL,
|
|
32
|
+
target_id TEXT NOT NULL,
|
|
33
|
+
link_role TEXT NOT NULL,
|
|
34
|
+
created_at TEXT NOT NULL,
|
|
35
|
+
PRIMARY KEY (evidence_id, target_type, target_id, link_role)
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
CREATE INDEX IF NOT EXISTS idx_evidence_links_target
|
|
39
|
+
ON evidence_links(target_type, target_id, link_role, created_at);
|
|
40
|
+
|
|
41
|
+
-- Backfill existing task-linked evidence as role 'supporting'.
|
|
42
|
+
INSERT OR IGNORE INTO evidence_links(evidence_id, target_type, target_id, link_role, created_at)
|
|
43
|
+
SELECT id, 'task', linked_task_id, 'supporting', created_at
|
|
44
|
+
FROM evidence
|
|
45
|
+
WHERE linked_task_id IS NOT NULL;
|
|
46
|
+
```
|
|
47
|
+
Vocabulary in use now: `target_type` is `task` or `agent_job`;
|
|
48
|
+
`link_role` is `supporting` or `code_context`. Reserve (do not emit yet)
|
|
49
|
+
`goal` / `workflow_run` / `decision` / `escalation` and
|
|
50
|
+
`master_trace` / `intent_index` / `worker_output`.
|
|
51
|
+
2. Write path: `pcl evidence add --task T-XXXX` (evidence.py) keeps setting the
|
|
52
|
+
`evidence.linked_task_id` column (0.x compat) and also inserts an
|
|
53
|
+
`evidence_links` row `(evidence_id, 'task', task_id, 'supporting', now)` in
|
|
54
|
+
the same transaction, before the existing `append_event`.
|
|
55
|
+
3. Read path: `context.py._linked_task_evidence` selects from `evidence_links`
|
|
56
|
+
where `target_type='task' AND link_role='supporting'`, joined to `evidence`
|
|
57
|
+
for the display columns, ordered `created_at, evidence_id`. When the
|
|
58
|
+
`evidence_links` table is absent (pre-migration DB opened by a newer binary
|
|
59
|
+
mid-upgrade), fall back to the current `linked_task_id` column query. Output
|
|
60
|
+
shape, ordering, and member/stored-path resolution are unchanged.
|
|
61
|
+
4. Strict validation (`validators.py`): add a dangling-link check modeled on the
|
|
62
|
+
verification `receipt_evidence_id` check (validators.py:596) — every
|
|
63
|
+
`evidence_links.evidence_id` must resolve to an existing evidence row (the
|
|
64
|
+
existing `PRAGMA foreign_key_check` already covers this; keep an explicit,
|
|
65
|
+
message-consistent check too), and for known target types the `target_id`
|
|
66
|
+
must exist (`task` maps to `tasks`, `agent_job` maps to `agent_jobs`).
|
|
67
|
+
Unknown `target_type` values are tolerated with no error (forward
|
|
68
|
+
compatibility).
|
|
69
|
+
5. Provide two small internal helpers for 0108 to reuse (no new CLI surface):
|
|
70
|
+
insert a link row, and select the newest `evidence_id` for a given
|
|
71
|
+
`(target_type, target_id, link_role)`.
|
|
72
|
+
|
|
73
|
+
## Invariants (what to protect, on the normal paths)
|
|
74
|
+
|
|
75
|
+
- The canonical write path for a task-linked ad-hoc evidence is, in one
|
|
76
|
+
transaction: the `evidence` row plus the `linked_task_id` column plus the
|
|
77
|
+
`evidence_links` row plus the `adhoc_evidence_recorded` event. Do not drop the
|
|
78
|
+
`linked_task_id` column write (compat). Do not write an `evidence_links` row
|
|
79
|
+
without its mirroring `evidence` row.
|
|
80
|
+
- The migration backfill is idempotent (`INSERT OR IGNORE`) and additive: it
|
|
81
|
+
must not update or delete any `evidence` row, and re-running `pcl migrate`
|
|
82
|
+
must be a no-op.
|
|
83
|
+
- `evidence_links` is written only through `pcl` (evidence add today, 0108
|
|
84
|
+
tomorrow). No command deletes links in this task; no raw-SQL mutation path.
|
|
85
|
+
- The existing task context-pack `linked_evidence` output — shape, ordering,
|
|
86
|
+
member/stored paths — is unchanged for existing DBs after backfill.
|
|
87
|
+
- Additive only: no existing table or column is dropped or repurposed. Schema
|
|
88
|
+
version advances 6 to 7; `never-downgrade` and DB-ahead typed rejection (0076)
|
|
89
|
+
continue to hold.
|
|
90
|
+
|
|
91
|
+
## Non-scope
|
|
92
|
+
|
|
93
|
+
- `pcl evidence link` / `unlink` CLI verbs (links are written implicitly by
|
|
94
|
+
`evidence add` and, in 0108, by `impact --for-task/--for-job`).
|
|
95
|
+
- Job / goal / decision linking commands beyond the helper 0108 needs.
|
|
96
|
+
- Dashboard changes. The existing `heading_evidence_links` locale string is an
|
|
97
|
+
unrelated UI heading, not this table.
|
|
98
|
+
- Removing or deprecating `linked_task_id` (deferred past 0.x).
|
|
99
|
+
- Reading `evidence_links` from the code-context receipt selection path (that is
|
|
100
|
+
0108).
|
|
101
|
+
|
|
102
|
+
## Acceptance
|
|
103
|
+
|
|
104
|
+
- Fresh `pcl init` gives schema v7, `evidence_links` present,
|
|
105
|
+
`pcl validate --strict --json` green.
|
|
106
|
+
- A v6 to v7 live migration backfills every `linked_task_id` row into
|
|
107
|
+
`evidence_links` as role `supporting`; backfilled row count equals the number
|
|
108
|
+
of non-null `linked_task_id` rows; a second `pcl migrate` changes nothing.
|
|
109
|
+
- `pcl evidence add --task T-0001` writes both the column and the
|
|
110
|
+
`evidence_links` row; the task context pack lists the evidence identically to
|
|
111
|
+
before.
|
|
112
|
+
- A hand-broken dangling link (an `evidence_links` row whose `target_type='task'`
|
|
113
|
+
`target_id` has no matching task) is reported by `validate --strict`; a row
|
|
114
|
+
with an unknown `target_type` is tolerated (no error).
|
|
115
|
+
- An older (v6-aware) `pcl` binary typed-rejects a v7 DB with
|
|
116
|
+
`schema_version_ahead` (0076 behavior preserved).
|
|
117
|
+
- Full `pytest` green; live smoke in a scratch project (`init`, then `evidence
|
|
118
|
+
add --task`, then `validate --strict`, then context pack).
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# 0114: Source hash drift detection for copied evidence
|
|
2
|
+
|
|
3
|
+
Milestone: v0.3.0 Target-Bound Context
|
|
4
|
+
Priority: P2
|
|
5
|
+
Area: evidence
|
|
6
|
+
Origin: docs/growth-plan-v0.2.4-v0.5.md 論点2; third-party review P1 / 議題2 —
|
|
7
|
+
default-on approved (坂本承認 2026-07-08). Extends 0102.
|
|
8
|
+
|
|
9
|
+
## Problem
|
|
10
|
+
|
|
11
|
+
`_collect_copied_member_findings` in `src/pcl/evidence.py` (the source-freshness
|
|
12
|
+
block at evidence.py:589-605) detects source drift only via `detail: "missing"`
|
|
13
|
+
and `detail: "size_mismatch"`. A **same-size content change** to the source
|
|
14
|
+
file is undetected: `source_drifted` never fires, so a copied evidence member
|
|
15
|
+
whose origin was silently rewritten to a different-but-equal-length body reads
|
|
16
|
+
as fresh. The recorded member `sha256` (`expected_sha256`) is already a
|
|
17
|
+
parameter of this function (evidence.py:545) but is never compared against the
|
|
18
|
+
current source.
|
|
19
|
+
|
|
20
|
+
0102 already classifies `source_drifted` as an evidence-health **warning**, so
|
|
21
|
+
closing this gap needs no health-model change — only the missing hash
|
|
22
|
+
comparison.
|
|
23
|
+
|
|
24
|
+
## Scope
|
|
25
|
+
|
|
26
|
+
1. In `_collect_copied_member_findings`, extend the `else` branch that currently
|
|
27
|
+
only handles the size check: when the source exists **and**
|
|
28
|
+
`source_stat.st_size == size_bytes`, compute the source file sha256 (reuse
|
|
29
|
+
`_sha256_file`, evidence.py:907) and compare to `expected_sha256`.
|
|
30
|
+
- Mismatch → append `{"code": "source_drifted", "path": member_path,
|
|
31
|
+
"detail": "hash_mismatch"}`.
|
|
32
|
+
- `OSError` while reading the source → treat as unreadable and reuse the
|
|
33
|
+
existing `detail: "missing"` finding (do not crash, do not add a new code).
|
|
34
|
+
2. Default-on, no `--deep` flag. The hash is computed **only** in the same-size
|
|
35
|
+
branch, so `missing` and `size_mismatch` stay the cheap fast paths. The
|
|
36
|
+
`copy_max_member_bytes` cap (10MB, 0097) bounds per-member cost.
|
|
37
|
+
3. Confirm the `validators.py` `source_drifted` rendering branch (the
|
|
38
|
+
`elif code == "source_drifted":` branch, ~line 977) renders the new
|
|
39
|
+
`hash_mismatch` detail consistently through the shared
|
|
40
|
+
`assess_adhoc_evidence` path (0095 pattern) — health stays `warning`.
|
|
41
|
+
|
|
42
|
+
## Invariants (what to protect, on the normal paths)
|
|
43
|
+
|
|
44
|
+
- Read-only assessment: no finding rewrites or removes copied artifacts under
|
|
45
|
+
`.project-loop/evidence/adhoc-files/` or any source file.
|
|
46
|
+
- Findings shape is additive-only: `source_drifted` gains one new `detail`
|
|
47
|
+
value, `hash_mismatch`. Existing `missing` / `size_mismatch` details, their
|
|
48
|
+
`path` field, and ordering are unchanged.
|
|
49
|
+
- Copied-artifact health stays semantically **separate** from source freshness
|
|
50
|
+
in wording (0102 invariant): `copy_hash_mismatch` = the copied artifact broke;
|
|
51
|
+
`source_drifted/hash_mismatch` = the origin changed since the copy. Do not
|
|
52
|
+
merge or cross-reference the two codes.
|
|
53
|
+
- Health stays the three-level `ok | warning | error`; no `artifact_health` /
|
|
54
|
+
`source_health` split (still deferred until dogfood `source_drift_rate` data).
|
|
55
|
+
|
|
56
|
+
## Non-scope
|
|
57
|
+
|
|
58
|
+
- A `--deep` / lightweight-vs-deep mode split (unnecessary: the size gate plus
|
|
59
|
+
the 10MB member cap already bound cost).
|
|
60
|
+
- Hashing sources of **reference** (non-copied) members — reference members are
|
|
61
|
+
already hash-checked against the source directly by `_assess_reference_member`.
|
|
62
|
+
- `artifact_health` / `source_health` field separation.
|
|
63
|
+
|
|
64
|
+
## Acceptance
|
|
65
|
+
|
|
66
|
+
- Test: copied artifact intact + source rewritten to different content of the
|
|
67
|
+
**same byte length** → `health: "warning"` with a `source_drifted` finding,
|
|
68
|
+
`detail: "hash_mismatch"`.
|
|
69
|
+
- Test: copied artifact intact + source intact → `health: "ok"` (no regression).
|
|
70
|
+
- Test: `copy_hash_mismatch` (artifact corrupted) + `source_drifted/hash_mismatch`
|
|
71
|
+
co-occur → still `warning`, both findings present, no double-count crash.
|
|
72
|
+
- `pcl validate --strict --json` treats `source_drifted/hash_mismatch` as a
|
|
73
|
+
warning that remains a warning under strict (extend
|
|
74
|
+
`_strict_warning_remains_warning` coverage) and stays green overall.
|
|
75
|
+
- Live smoke: in a scratch project, `evidence add --copy` a file, edit the
|
|
76
|
+
source to same-length different content, `pcl validate --strict --json` →
|
|
77
|
+
evidence health `warning`, detail `hash_mismatch`, strict `ok: true`.
|
|
78
|
+
- Full `pytest` green; release note entry describing the tightened semantics.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# 0115: Context pack target-bound contract fixtures
|
|
2
|
+
|
|
3
|
+
Milestone: v0.3.0 Target-Bound Context
|
|
4
|
+
Priority: P2
|
|
5
|
+
Area: context-pack/tests
|
|
6
|
+
Origin: docs/growth-plan-v0.2.4-v0.5.md v0.3.0; third-party review 0111 —
|
|
7
|
+
required in v0.3.0 (坂本承認 2026-07-08). Depends on 0108 and 0113.
|
|
8
|
+
|
|
9
|
+
## Problem
|
|
10
|
+
|
|
11
|
+
0108 changes the `context-pack/v1` code-context contract: `code_context.relevance`
|
|
12
|
+
gains `scope: "target_bound"` / `binding_strength: "caller_asserted"` with
|
|
13
|
+
`target_type` / `target_id`, a `receipt_ref`, a `--require-bound-receipt` typed
|
|
14
|
+
error, and target-specific `suggested_refresh_commands`. PLH has shipped three
|
|
15
|
+
contract regressions caught only in review (0087 git-status key loss, 0089
|
|
16
|
+
audit-mirror break, 0090 receipt-content storage). Freeze the v0.3.0 handoff
|
|
17
|
+
contract with deterministic fixture-based tests so future changes are provably
|
|
18
|
+
additive and any silent shape change fails a test.
|
|
19
|
+
|
|
20
|
+
## Scope
|
|
21
|
+
|
|
22
|
+
Add fixture-backed tests covering six code-context selection states. Each
|
|
23
|
+
fixture asserts `included_sections`, the required / non-droppable safety
|
|
24
|
+
sections, `source_paths`, `suggested_refresh_commands`, and
|
|
25
|
+
`code_context.relevance`:
|
|
26
|
+
|
|
27
|
+
1. **no receipt** — `scope: "missing_receipt"`, `binding_strength: "none"`.
|
|
28
|
+
2. **unscoped latest only** — a receipt with no `target_binding`;
|
|
29
|
+
`scope: "unscoped_latest"`, `binding_strength: "none"`, with the existing
|
|
30
|
+
unscoped warning and a target-specific suggested refresh command.
|
|
31
|
+
3. **matching task-bound receipt** — `scope: "target_bound"`,
|
|
32
|
+
`binding_strength: "caller_asserted"`, `target_type: "task"`, `target_id`
|
|
33
|
+
set; chosen over a newer unbound receipt.
|
|
34
|
+
4. **matching job-bound receipt** — same as (3) with `target_type: "agent_job"`.
|
|
35
|
+
5. **stale bound receipt** — a matching bound receipt old enough that the 0082
|
|
36
|
+
`age_warning` fires; relevance stays `target_bound` and the age warning is
|
|
37
|
+
present (staleness is a surfaced fact, not a downgrade).
|
|
38
|
+
6. **require-bound missing** — `--require-bound-receipt` with no matching bound
|
|
39
|
+
receipt → typed error `context_pack_bound_receipt_required` with the
|
|
40
|
+
target-specific refresh suggestion; assert there is **no** silent fallback to
|
|
41
|
+
unscoped latest.
|
|
42
|
+
|
|
43
|
+
## Invariants (what to protect, on the normal paths)
|
|
44
|
+
|
|
45
|
+
- Fixtures are byte-deterministic: inject `now` at the CLI boundary the way
|
|
46
|
+
existing pack tests do; no wall-clock reads inside generated artifacts.
|
|
47
|
+
- Budget truncation never drops required safety sections: the
|
|
48
|
+
`code_context_safety` pin (priority 10000, 0078/0083) survives a deliberately
|
|
49
|
+
tight budget — at least one fixture asserts this.
|
|
50
|
+
- Contract assertions are additive-only in spirit: adding a new field is
|
|
51
|
+
allowed; changing or removing an asserted field, shape, or ordering must fail
|
|
52
|
+
a fixture. Do not weaken an assertion to make a change pass.
|
|
53
|
+
- Fixtures must not inline receipt bodies or copied evidence file contents
|
|
54
|
+
(0090 boundary): assert `receipt_ref` carries `evidence_id` / `receipt_path`
|
|
55
|
+
only.
|
|
56
|
+
|
|
57
|
+
## Non-scope
|
|
58
|
+
|
|
59
|
+
- Any new runtime behavior — this is a pure test / fixture task. If a fixture
|
|
60
|
+
reveals a 0108 defect, fix it in 0108, not here.
|
|
61
|
+
- Dashboard, MCP, or CLI-surface changes.
|
|
62
|
+
- Golden-file snapshotting of the entire pack (assert the contract-bearing
|
|
63
|
+
fields, not incidental whitespace).
|
|
64
|
+
|
|
65
|
+
## Acceptance
|
|
66
|
+
|
|
67
|
+
- Six fixtures committed and green.
|
|
68
|
+
- A deliberate contract break (e.g., dropping `binding_strength` from
|
|
69
|
+
`relevance`, or letting `--require-bound-receipt` fall back silently) makes at
|
|
70
|
+
least one fixture fail with a clear message.
|
|
71
|
+
- The tight-budget fixture proves the safety section is never truncated away.
|
|
72
|
+
- Full `pytest` green.
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# 0116: Target-bound receipt / link agreement validation
|
|
2
|
+
|
|
3
|
+
Milestone: v0.3.1 Handoff Integrity + Operator Experience
|
|
4
|
+
Priority: P1
|
|
5
|
+
Area: context/validation
|
|
6
|
+
Origin: third-party v0.3.0 post-release review (P1①). Sakamoto approved the
|
|
7
|
+
recommended plan 2026-07-09 (integrity pair 0116+0117 first).
|
|
8
|
+
|
|
9
|
+
## Problem
|
|
10
|
+
|
|
11
|
+
v0.3.0 selects a target-bound code-context receipt purely from the
|
|
12
|
+
`evidence_links` routing row plus the evidence type. `_select_code_context_receipt_ref`
|
|
13
|
+
(`context.py:780-791`) reads `newest_linked_evidence_id(... link_role="code_context")`,
|
|
14
|
+
loads the evidence row, checks only `evidence_type == context_receipt`, and returns
|
|
15
|
+
`"target_bound"`. Downstream, `_latest_code_context_summary` (`context.py:725-751`)
|
|
16
|
+
loads the receipt artifact but **never compares the artifact's `target_binding`
|
|
17
|
+
to the requested pack target**, and `_code_context_relevance` (`context.py:857`)
|
|
18
|
+
stamps `scope: target_bound` from `selection_scope` alone. Strict validation
|
|
19
|
+
(`_validate_evidence_links`, `validators.py:621-659`) only checks dangling links
|
|
20
|
+
(evidence row exists; `target_id` exists in `tasks`/`agent_jobs`); it does not
|
|
21
|
+
read the artifact binding either.
|
|
22
|
+
|
|
23
|
+
On the normal write path this cannot break: 0108 writes the `evidence_links`
|
|
24
|
+
row and the artifact `target_binding` in one transaction with the same target,
|
|
25
|
+
and inserts the `code_context` link **only when `target_binding is not None`**
|
|
26
|
+
(`code_context/receipts.py:123-129`). But a hand-edited DB, a future writer bug,
|
|
27
|
+
a migration accident, or raw SQL can leave the link routing a receipt whose
|
|
28
|
+
artifact binding names a *different* target. Today that receipt would surface as
|
|
29
|
+
`scope: target_bound` for the wrong target — the exact "target-bound label that
|
|
30
|
+
lies" failure this milestone must foreclose.
|
|
31
|
+
|
|
32
|
+
This is defense-in-depth / corruption resilience, not a normal-path bug. The
|
|
33
|
+
guarantee to establish: **nothing is ever reported as `target_bound` unless the
|
|
34
|
+
selected receipt artifact's own `target_binding` agrees with the requested
|
|
35
|
+
target.**
|
|
36
|
+
|
|
37
|
+
## Scope
|
|
38
|
+
|
|
39
|
+
### 1. Agreement predicate (single reusable helper)
|
|
40
|
+
|
|
41
|
+
Add one pure helper (in `context.py`, or a small shared location `pcl context
|
|
42
|
+
check` (0119) can also import — do not duplicate this logic later):
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
def _receipt_target_binding_agrees(
|
|
46
|
+
receipt_payload: dict[str, Any], *, target_type: str, target_id: str
|
|
47
|
+
) -> bool:
|
|
48
|
+
binding = receipt_payload.get("target_binding")
|
|
49
|
+
if not isinstance(binding, dict):
|
|
50
|
+
return False # a code_context-linked artifact with no binding is anomalous
|
|
51
|
+
return (
|
|
52
|
+
str(binding.get("target_type")) == target_type
|
|
53
|
+
and str(binding.get("target_id")) == target_id
|
|
54
|
+
)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Missing / non-dict `target_binding` on a receipt reached through a `code_context`
|
|
58
|
+
link counts as **disagreement** (per the 0108 invariant such a link always has a
|
|
59
|
+
binding, so its absence is corruption).
|
|
60
|
+
|
|
61
|
+
### 2. Read-side guard in selection
|
|
62
|
+
|
|
63
|
+
In `_select_code_context_receipt_ref`, after obtaining the candidate
|
|
64
|
+
`receipt_ref` from the link and confirming `evidence_type == context_receipt`,
|
|
65
|
+
load the receipt artifact (reuse `resolve_context_receipt_path` +
|
|
66
|
+
`json.loads`, both already used at `context.py:725-727`):
|
|
67
|
+
|
|
68
|
+
- **Artifact load fails** (OSError / JSONDecodeError / not a dict): NOT a
|
|
69
|
+
mismatch. Preserve current behavior — return `(_public_receipt_ref(...),
|
|
70
|
+
"target_bound")` and let `_latest_code_context_summary` render
|
|
71
|
+
`receipt_unavailable`. (Unreadable ≠ disagreement; do not turn transient FS
|
|
72
|
+
errors into mismatches.)
|
|
73
|
+
- **Artifact loads and binding agrees**: return `(ref, "target_bound")` (today's
|
|
74
|
+
happy path, unchanged).
|
|
75
|
+
- **Artifact loads and binding disagrees** (including missing/blank binding):
|
|
76
|
+
MISMATCH.
|
|
77
|
+
- `require_bound_receipt=True` → raise a new distinct
|
|
78
|
+
`ContextPackBoundReceiptMismatchError` (see §3). Do **not** raise the
|
|
79
|
+
existing `...RequiredError` — the operator must be able to tell "corrupt
|
|
80
|
+
binding" from "no receipt".
|
|
81
|
+
- `require_bound_receipt=False` → skip this receipt and fall through to the
|
|
82
|
+
existing `latest_context_receipt_ref` path, returning `"unscoped_latest"`
|
|
83
|
+
(or `"missing_receipt"` if none). It MUST NOT return `"target_bound"`.
|
|
84
|
+
SHOULD: surface that a mismatched bound link was skipped in the
|
|
85
|
+
`unscoped_latest` relevance `warning` (distinct wording from plain "no
|
|
86
|
+
target-bound receipt found"); if threading a flag is awkward, the MUST
|
|
87
|
+
(never `target_bound`) is sufficient for this task.
|
|
88
|
+
|
|
89
|
+
### 3. New typed error
|
|
90
|
+
|
|
91
|
+
Add `ContextPackBoundReceiptMismatchError(PclError)` modeled on
|
|
92
|
+
`ContextPackBoundReceiptRequiredError` (`context.py:47-58`):
|
|
93
|
+
|
|
94
|
+
- `code = "context_pack_bound_receipt_mismatch"`, `exit_code = EXIT_USAGE`.
|
|
95
|
+
- `message`: names the target and that a linked receipt's binding disagrees.
|
|
96
|
+
- `details`: `target_type`, `target_id`, the offending `evidence_id`, the
|
|
97
|
+
artifact's claimed `target_binding` (as read), and
|
|
98
|
+
`suggested_refresh_commands = [_target_refresh_command(target_type, target_id)]`.
|
|
99
|
+
|
|
100
|
+
### 4. Strict-validation agreement check
|
|
101
|
+
|
|
102
|
+
Thread `ProjectPaths` into the evidence-links validation (`validate_project`
|
|
103
|
+
already has `paths` at `validators.py:110`; update the call site
|
|
104
|
+
`_validate_evidence_links(conn, result)` at `validators.py:266`). For each
|
|
105
|
+
`evidence_links` row with `link_role == "code_context"` and a **known**
|
|
106
|
+
`target_type`:
|
|
107
|
+
|
|
108
|
+
- Resolve the receipt artifact via `evidence_ref_by_id(paths, evidence_id)` +
|
|
109
|
+
`resolve_context_receipt_path`.
|
|
110
|
+
- If the artifact is **readable** and its `target_binding` disagrees with the
|
|
111
|
+
row's `(target_type, target_id)` (using the §1 predicate), `result.add_error`
|
|
112
|
+
with a message naming the link, the row target, and the artifact's claimed
|
|
113
|
+
binding.
|
|
114
|
+
- If the artifact is **missing/unreadable**, add no new error here (existing
|
|
115
|
+
evidence-health / dangling checks own that surface; avoid double-reporting).
|
|
116
|
+
|
|
117
|
+
Only `code_context` links are checked (supporting links have no artifact
|
|
118
|
+
binding). Unknown `target_type` stays tolerated (no error), as in 0113.
|
|
119
|
+
|
|
120
|
+
## Invariants (what to protect, on the normal paths)
|
|
121
|
+
|
|
122
|
+
- Normal-path target-bound selection and output are byte-for-byte unchanged: a
|
|
123
|
+
receipt whose artifact binding matches keeps `scope: target_bound` /
|
|
124
|
+
`binding_strength: caller_asserted` and the same `receipt_ref`.
|
|
125
|
+
- No new claim vocabulary. Binding stays `caller_asserted`; no
|
|
126
|
+
`verified_relevant` / `safe_to_continue` / `agent_read` / semantic wording.
|
|
127
|
+
A mismatch error states a *fact* ("the routing row and the artifact binding
|
|
128
|
+
disagree"), never a judgment about relevance.
|
|
129
|
+
- `pcl` remains the only mutation path; this task adds read-side checks only and
|
|
130
|
+
writes nothing.
|
|
131
|
+
- Additive: no schema change (schema stays 7), no migration, no new table or
|
|
132
|
+
column. `require_human_approval: database_migration` does NOT apply.
|
|
133
|
+
|
|
134
|
+
## Non-scope
|
|
135
|
+
|
|
136
|
+
- `pcl context check` (0119) — it will import the §1 predicate; do not build the
|
|
137
|
+
command here.
|
|
138
|
+
- Auto-repair / re-linking of a mismatched link. Detection and safe refusal
|
|
139
|
+
only; never mutate `evidence_links` to "fix" a mismatch.
|
|
140
|
+
- Any change to the 0108 write path (it is already correct and atomic).
|
|
141
|
+
- Markdown refresh-command wording (that is 0117).
|
|
142
|
+
|
|
143
|
+
## Acceptance
|
|
144
|
+
|
|
145
|
+
- New helper is unit-tested: agrees on matching binding; disagrees on
|
|
146
|
+
mismatched target, on missing `target_binding`, and on non-dict payload.
|
|
147
|
+
- Contract fixture added (extend the 0115 code-context contract set): an
|
|
148
|
+
`evidence_links` `code_context` row pointing at target A while the artifact
|
|
149
|
+
`target_binding` names target B —
|
|
150
|
+
- `--require-bound-receipt` → error
|
|
151
|
+
`context_pack_bound_receipt_mismatch` (not `..._required`);
|
|
152
|
+
- default (no require) → `code_context.relevance.scope` is `unscoped_latest`
|
|
153
|
+
or `missing_receipt`, **never** `target_bound`.
|
|
154
|
+
- `validate --strict --json` reports the hand-built mismatch row as an error;
|
|
155
|
+
an agreeing `code_context` row and any `supporting` row produce no new error;
|
|
156
|
+
an unknown `target_type` row is still tolerated.
|
|
157
|
+
- All existing target-bound / require / unscoped tests stay green (normal path
|
|
158
|
+
unaffected).
|
|
159
|
+
- Full `pytest` green; live smoke in a scratch project proving: a normal
|
|
160
|
+
`impact --for-task` + `context pack --require-bound-receipt` still selects
|
|
161
|
+
`target_bound`, and a deliberately corrupted link (built through `pcl`-created
|
|
162
|
+
state, then the `.db` row's `target_id` diverged for the test only) yields the
|
|
163
|
+
mismatch error under `--require-bound-receipt` and `unscoped_latest` without.
|