sayfirst-cli 0.3.1__tar.gz → 0.3.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 (110) hide show
  1. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/CHANGELOG.md +7 -0
  2. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/PKG-INFO +9 -7
  3. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/QUICKSTART.md +13 -12
  4. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/README.md +6 -4
  5. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/docs/PACKS.md +3 -1
  6. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/pyproject.toml +3 -3
  7. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/instrument/launch.py +1 -1
  8. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/.github/workflows/ci.yml +0 -0
  9. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/.github/workflows/release.yml +0 -0
  10. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/.gitignore +0 -0
  11. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/LICENSE +0 -0
  12. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/NOTICE +0 -0
  13. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/SECURITY.md +0 -0
  14. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/TRADEMARKS.md +0 -0
  15. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/docs/EVIDENCE-SURFACE.md +0 -0
  16. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/docs/PARTITION.md +0 -0
  17. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/docs/PROVENANCE.md +0 -0
  18. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/docs/publication-checklist.md +0 -0
  19. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/scripts/check_dependency_closure.py +0 -0
  20. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/scripts/check_developer_certificate_of_origin.py +0 -0
  21. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/scripts/gate.sh +0 -0
  22. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/scripts/release_version.py +0 -0
  23. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/__init__.py +0 -0
  24. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/approvals.py +0 -0
  25. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/ask.py +0 -0
  26. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/evidence.py +0 -0
  27. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/exit_codes.py +0 -0
  28. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/explain.py +0 -0
  29. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/instrument/__init__.py +0 -0
  30. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/instrument/_bootstrap/sitecustomize.py +0 -0
  31. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/instrument/commands.py +0 -0
  32. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/instrument/designation.py +0 -0
  33. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/instrument/engine.py +0 -0
  34. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/instrument/follow.py +0 -0
  35. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/instrument/harness.py +0 -0
  36. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/instrument/interpreter.py +0 -0
  37. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/instrument/manifest.py +0 -0
  38. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/instrument/verify.py +0 -0
  39. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/main.py +0 -0
  40. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/packs/__init__.py +0 -0
  41. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/packs/database/NOTE.md +0 -0
  42. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/packs/database/interpose.py +0 -0
  43. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/packs/database/pack.toml +0 -0
  44. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/packs/http-client/NOTE.md +0 -0
  45. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/packs/http-client/interpose.py +0 -0
  46. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/packs/http-client/pack.toml +0 -0
  47. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/packs/subprocess/NOTE.md +0 -0
  48. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/packs/subprocess/interpose.py +0 -0
  49. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/packs/subprocess/pack.toml +0 -0
  50. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/packs_cmd.py +0 -0
  51. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/pages.py +0 -0
  52. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/reads.py +0 -0
  53. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/render.py +0 -0
  54. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/src/sayfirst_cli/trace.py +0 -0
  55. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/canned_daemon.py +0 -0
  56. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/conftest.py +0 -0
  57. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/contract_absence.py +0 -0
  58. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/documents.py +0 -0
  59. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/governed_programs.py +0 -0
  60. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/pack_doubles.py +0 -0
  61. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/replies.py +0 -0
  62. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_approvals.py +0 -0
  63. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_ask_connection_loss.py +0 -0
  64. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_ask_end_to_end.py +0 -0
  65. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_boundary_runtime.py +0 -0
  66. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_changelog_names_the_version.py +0 -0
  67. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_contract_absence.py +0 -0
  68. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_contract_words.py +0 -0
  69. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_database_pack.py +0 -0
  70. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_decided_name.py +0 -0
  71. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_default_socket.py +0 -0
  72. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_dependency_closure.py +0 -0
  73. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_developer_certificate_of_origin.py +0 -0
  74. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_engine.py +0 -0
  75. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_engine_is_agnostic.py +0 -0
  76. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_evidence_export_and_exports.py +0 -0
  77. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_evidence_history_and_audit.py +0 -0
  78. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_evidence_reads.py +0 -0
  79. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_exit_codes.py +0 -0
  80. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_follow_children.py +0 -0
  81. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_gate_modes.py +0 -0
  82. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_governed_run_leaves_no_trace.py +0 -0
  83. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_http_client_pack.py +0 -0
  84. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_instrument_run.py +0 -0
  85. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_instrument_verify.py +0 -0
  86. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_interpreter_target.py +0 -0
  87. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_manifest.py +0 -0
  88. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_offline_audit_vectors.py +0 -0
  89. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_pack_designation.py +0 -0
  90. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_pack_doubles.py +0 -0
  91. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_packs_cmd.py +0 -0
  92. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_packs_shipped.py +0 -0
  93. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_partition_boundary.py +0 -0
  94. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_pointers_survive_publication.py +0 -0
  95. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_public_vocabulary.py +0 -0
  96. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_publication_checklist_names_every_act.py +0 -0
  97. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_quickstart_names_what_exists.py +0 -0
  98. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_read_rendering.py +0 -0
  99. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_reads.py +0 -0
  100. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_release_workflow_publishes_only_on_a_tag.py +0 -0
  101. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_review_bounds.py +0 -0
  102. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_running_the_module.py +0 -0
  103. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_shipped_wheel_notices.py +0 -0
  104. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_source_distribution_notices.py +0 -0
  105. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_spdx_identifiers.py +0 -0
  106. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_subprocess_pack.py +0 -0
  107. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_trace_and_explain.py +0 -0
  108. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_verification_claims_what_it_established.py +0 -0
  109. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_verify_asks_every_effect.py +0 -0
  110. {sayfirst_cli-0.3.1 → sayfirst_cli-0.3.2}/tests/test_verify_pairs_an_inner_spawn.py +0 -0
@@ -6,6 +6,13 @@ declares; a release with no section fails the gate.
6
6
 
7
7
  ## Unreleased
8
8
 
9
+ ## 0.3.2
10
+
11
+ - The contract and the boundary move to 0.3.2, which carries security fixes.
12
+ Under `sayfirst instrument run`, an act a person approved now runs once;
13
+ asked again, it waits under a new approval.
14
+ - The pages say that an allow produced by an approval carries no grant.
15
+
9
16
  ## 0.3.1
10
17
 
11
18
  - **`instrument verify` says how a run ended when the program raised, too.** The harness said
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: sayfirst-cli
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Summary: The product command-line interface of the sayfirst control plane
5
5
  Project-URL: Repository, https://github.com/fredaime/sayfirst-cli
6
6
  Project-URL: Documentation, https://github.com/fredaime/sayfirst-cli/blob/main/README.md
@@ -15,8 +15,8 @@ Classifier: Programming Language :: Python :: 3.12
15
15
  Classifier: Programming Language :: Python :: 3.13
16
16
  Classifier: Programming Language :: Python :: 3.14
17
17
  Requires-Python: <3.15,>=3.12
18
- Requires-Dist: sayfirst-boundary==0.3.1
19
- Requires-Dist: sayfirst-contract==0.3.1
18
+ Requires-Dist: sayfirst-boundary==0.3.2
19
+ Requires-Dist: sayfirst-contract==0.3.2
20
20
  Description-Content-Type: text/markdown
21
21
 
22
22
  <!-- SPDX-License-Identifier: Apache-2.0 -->
@@ -36,7 +36,9 @@ anything that matters: *may I do this, with these arguments, as this account?*
36
36
  person can read, over a Unix socket that tells it who is asking from the
37
37
  kernel's own credentials. No URL, no token, nothing to leak (article 6).
38
38
  - **The program never decides.** It asks, and it does only what was allowed:
39
- the boundary (`sayfirst-boundary`) holds the grant for exactly one execution.
39
+ the boundary (`sayfirst-boundary`) holds the grant a policy allow serves, for the run;
40
+ an allow that a person's approval produced carries no grant — it runs the act
41
+ once, and the same act asked again waits under a new approval.
40
42
  - **A person is in the loop by construction, not by dashboard.** A suspension
41
43
  is a wait. `sayfirst approvals approve` ends it once, the deadline comes from
42
44
  the policy, and a rejection stands until that deadline, or until the daemon
@@ -114,7 +116,7 @@ command on that page was run, in that order, before it was written down.
114
116
 
115
117
  ### What the index holds
116
118
 
117
- Everything the three commands above need is on the Python index at 0.3.1:
119
+ Everything the three commands above need is on the Python index at 0.3.2:
118
120
  `sayfirst-cli`, the `sayfirst-contract` it speaks and the `sayfirst-boundary` a
119
121
  governed program holds its grants in, and the control plane's
120
122
  `sayfirst-control-plane` and `sayfirstd`. The first command installs all five
@@ -247,7 +249,7 @@ contract is built from a checkout of the control plane's repository, at the tag
247
249
  this client pins:
248
250
 
249
251
  ```console
250
- $ SAYFIRST_CONTRACT_SOURCE=../sayfirst-control-plane SAYFIRST_CONTRACT_REF=v0.3.1 ./scripts/gate.sh
252
+ $ SAYFIRST_CONTRACT_SOURCE=../sayfirst-control-plane SAYFIRST_CONTRACT_REF=v0.3.2 ./scripts/gate.sh
251
253
  ```
252
254
 
253
255
  The workflow does the same and carries no credential of any kind: a fork can
@@ -274,7 +276,7 @@ GitHub's private reporting, never a public issue — [`LICENSE`](LICENSE),
274
276
 
275
277
  ## Status
276
278
 
277
- **0.2.0 is the first public release**, 2026-09-17. 0.3.1 is the current one.
279
+ **0.2.0 is the first public release**, 2026-09-17. 0.3.2 is the current one.
278
280
  What is *not* here is named too, because a surface a reader assumes is an
279
281
  overclaim: `connect`, `profile`, `whoami`, `integrate` and `version` are in
280
282
  [`docs/PARTITION.md`](docs/PARTITION.md) and none of them exists here.
@@ -12,8 +12,8 @@ $ sayfirst instrument run --pack subprocess --scope local -- python3 my_agent.py
12
12
 
13
13
  Everything on this page was run, in this order, before it was written down: the
14
14
  commands are pasted from that run, and so are their answers. The run installed
15
- 0.3.1 with the first command from wheels built from the two release trees,
16
- given `--no-index` (the walk ran before 0.3.1 reached the index; « From
15
+ 0.3.2 with the first command from wheels built from the two release trees,
16
+ given `--no-index` (the walk ran before 0.3.2 reached the index; « From
17
17
  checkouts instead » below is that install), on a PATH with `python3` and no
18
18
  `python`, in a shell with neither repository on any path, under a home
19
19
  directory made for it;
@@ -29,11 +29,12 @@ hashes will differ; the shapes will not.
29
29
  and macOS name it that; inside an activated virtual environment `python`
30
30
  works too), and [`uv`](https://docs.astral.sh/uv/). The walk used
31
31
  uv 0.12.
32
- - A home directory that only you can write. The daemon refuses a directory a
33
- group can write and that is not sticky: below the socket as
34
- `socket_directory_unprotected`, and above the policy as
35
- `policy_unavailable_at_start … exposed: group_write`; either way it says so
36
- instead of starting.
32
+ - A home directory that only you can write. The daemon refuses to start if
33
+ the socket's directory, or any directory on the way to it, can be written
34
+ by a group or by others and is not sticky (`socket_directory_unprotected`),
35
+ and likewise for the policy's directory and those above it
36
+ (`policy_unavailable_at_start … exposed: group_write`); either way it says
37
+ so instead of starting.
37
38
 
38
39
  ## 1. Install
39
40
 
@@ -42,11 +43,11 @@ $ uv tool install sayfirst-cli --with-executables-from sayfirst-control-plane --
42
43
  Resolved 5 packages in 3ms
43
44
  Prepared 5 packages in 6ms
44
45
  Installed 5 packages in 1ms
45
- + sayfirst-boundary==0.3.1
46
- + sayfirst-cli==0.3.1
47
- + sayfirst-contract==0.3.1
48
- + sayfirst-control-plane==0.3.1
49
- + sayfirstd==0.3.1
46
+ + sayfirst-boundary==0.3.2
47
+ + sayfirst-cli==0.3.2
48
+ + sayfirst-contract==0.3.2
49
+ + sayfirst-control-plane==0.3.2
50
+ + sayfirstd==0.3.2
50
51
  Installed 1 executable from `sayfirst-control-plane`: sayfirst-daemon
51
52
  Installed 1 executable from `sayfirstd`: sayfirstd
52
53
  Installed 1 executable: sayfirst
@@ -15,7 +15,9 @@ anything that matters: *may I do this, with these arguments, as this account?*
15
15
  person can read, over a Unix socket that tells it who is asking from the
16
16
  kernel's own credentials. No URL, no token, nothing to leak (article 6).
17
17
  - **The program never decides.** It asks, and it does only what was allowed:
18
- the boundary (`sayfirst-boundary`) holds the grant for exactly one execution.
18
+ the boundary (`sayfirst-boundary`) holds the grant a policy allow serves, for the run;
19
+ an allow that a person's approval produced carries no grant — it runs the act
20
+ once, and the same act asked again waits under a new approval.
19
21
  - **A person is in the loop by construction, not by dashboard.** A suspension
20
22
  is a wait. `sayfirst approvals approve` ends it once, the deadline comes from
21
23
  the policy, and a rejection stands until that deadline, or until the daemon
@@ -93,7 +95,7 @@ command on that page was run, in that order, before it was written down.
93
95
 
94
96
  ### What the index holds
95
97
 
96
- Everything the three commands above need is on the Python index at 0.3.1:
98
+ Everything the three commands above need is on the Python index at 0.3.2:
97
99
  `sayfirst-cli`, the `sayfirst-contract` it speaks and the `sayfirst-boundary` a
98
100
  governed program holds its grants in, and the control plane's
99
101
  `sayfirst-control-plane` and `sayfirstd`. The first command installs all five
@@ -226,7 +228,7 @@ contract is built from a checkout of the control plane's repository, at the tag
226
228
  this client pins:
227
229
 
228
230
  ```console
229
- $ SAYFIRST_CONTRACT_SOURCE=../sayfirst-control-plane SAYFIRST_CONTRACT_REF=v0.3.1 ./scripts/gate.sh
231
+ $ SAYFIRST_CONTRACT_SOURCE=../sayfirst-control-plane SAYFIRST_CONTRACT_REF=v0.3.2 ./scripts/gate.sh
230
232
  ```
231
233
 
232
234
  The workflow does the same and carries no credential of any kind: a fork can
@@ -253,7 +255,7 @@ GitHub's private reporting, never a public issue — [`LICENSE`](LICENSE),
253
255
 
254
256
  ## Status
255
257
 
256
- **0.2.0 is the first public release**, 2026-09-17. 0.3.1 is the current one.
258
+ **0.2.0 is the first public release**, 2026-09-17. 0.3.2 is the current one.
257
259
  What is *not* here is named too, because a surface a reader assumes is an
258
260
  overclaim: `connect`, `profile`, `whoami`, `integrate` and `version` are in
259
261
  [`docs/PARTITION.md`](docs/PARTITION.md) and none of them exists here.
@@ -237,7 +237,9 @@ is stepped over when any of them does not.
237
237
  are not the same order. **Which is why a verifying run holds no grant.**
238
238
  Under `instrument run` the boundary keeps what it was granted (article 10),
239
239
  and an identical effect repeated while that grant lives is answered by it
240
- with nothing asked and nothing recorded. Under `verify` the boundary in front
240
+ with nothing asked and nothing recorded. An allow that a person's approval
241
+ produced carries no grant: it runs the act once, and the same act asked again
242
+ waits under a new approval. Under `verify` the boundary in front
241
243
  of the program asks for every effect, so every effect has a record of its
242
244
  own: a program that spawns the same command twice is two decisions there,
243
245
  and one there would read the second spawn as ungoverned.
@@ -1,7 +1,7 @@
1
1
  # SPDX-License-Identifier: Apache-2.0
2
2
  [project]
3
3
  name = "sayfirst-cli"
4
- version = "0.3.1"
4
+ version = "0.3.2"
5
5
  description = "The product command-line interface of the sayfirst control plane"
6
6
  readme = "README.md"
7
7
  requires-python = ">=3.12,<3.15"
@@ -20,7 +20,7 @@ classifiers = [
20
20
  # promise made here — it is measured after an install. `sayfirst-boundary` joins
21
21
  # it because a governed program holds a grant in it (article 10); it depends on
22
22
  # the contract only, and it is not the server (article 14).
23
- dependencies = ["sayfirst-contract==0.3.1", "sayfirst-boundary==0.3.1"]
23
+ dependencies = ["sayfirst-contract==0.3.2", "sayfirst-boundary==0.3.2"]
24
24
 
25
25
  # The public repository this distribution sends a reader to, created fresh in
26
26
  # the act that published it (2026-09-17) under the names the operator chose for
@@ -41,7 +41,7 @@ sayfirst = "sayfirst_cli.main:run"
41
41
  dev = [
42
42
  "pytest==8.4.1",
43
43
  "ruff==0.12.12",
44
- "sayfirst-contract[stub]==0.3.1",
44
+ "sayfirst-contract[stub]==0.3.2",
45
45
  ]
46
46
 
47
47
  [build-system]
@@ -152,7 +152,7 @@ def run(
152
152
 
153
153
  `hold_grants=False` asks for every effect and holds no grant. The verifier
154
154
  runs this way: its proof is one recorded decision for each effect it saw,
155
- and a grant hit — an identical effect answered by an earlier allow, which is
155
+ and a grant hit — an identical effect answered by an earlier allow the policy gave, which is
156
156
  what `run` does (article 10) — records nothing, so a repeated effect would
157
157
  read as ungoverned.
158
158
  """
File without changes
File without changes
File without changes
File without changes
File without changes