Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,18 +283,18 @@ git -C <path> push -u origin shape/update-<sha> # then open a pull request

1. **`check` first, always.** It writes nothing and prints one verdict per
PINNED file: `unchanged`, `upstream-changed`, `locally-modified` (the project
edited its own copy), `both`, `already-at-target`, `upstream-removed`,
`unmapped` or `copy-missing`; `apply` refuses the last three. A file with no
row in `contracts/shape-pin.yaml` is not a shape copy and is none of your
business — an adopted project merged some of them away on purpose.
edited its own copy), `both`, `already-at-target`, `merged-away` (a `shape/`
copy merged into its own file and removed: `apply` drops its row),
`upstream-removed`, `unmapped` or `copy-missing`; `apply` refuses the last
three. A file with no row is not a shape copy and is none of your business.
2. **Show the human the verdicts and let them say yes.** Re-pinning records
which openRepoShape this project is a copy of. Do not pass `--yes` on your
own initiative.
3. **Never pass `--accept-local` to make a refusal go away.** It re-pins a
locally edited file FROM THE PROJECT'S OWN BYTES, which makes the drift
`validate-pins.py` reports today invisible. Whether the project keeps its
edit is the human's decision; the other two exits are to revert it or to
carry it upstream.
carry it upstream. No `NEXT` line passes it: `apply` refuses, and asks.
4. **`both` is a merge, and the tool refuses it unless you say `--accept-local
<path>` too.** Merge by hand, commit, then re-run with `--accept-local
<path>` on the file you merged — that commit goes on the branch `apply` is
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1041,9 +1041,9 @@ HAND: re-copy, re-pin, re-validate. `update-shape.py` is that, as one command:
product: **`unchanged`**, **`upstream-changed`** (the bytes differ between the
pinned commit and the target), **`locally-modified`** (the project's bytes
differ from the pinned digest — drift it introduced) or **`both`**; also
`already-at-target` (the root has the target's bytes) and `upstream-removed`,
`unmapped` and `copy-missing`; `apply` refuses the last three. It exits 1 when
there is anything to do, so it can be a scheduled job.
`already-at-target` (the root has the target's bytes), `merged-away` (below),
`upstream-removed`, `unmapped` and `copy-missing`; `apply` refuses the last
three. It exits 1 when there is anything to do, so it can be a scheduled job.

`apply` copies the `upstream-changed` files, rewrites `contracts/shape-pin.yaml`
(`commit`, `digests.tree_sha256` recomputed over the upstream tree under the
Expand All @@ -1066,9 +1066,9 @@ copying the upstream bytes over that would delete it without saying so.
**Only the pin's own rows are RE-SYNCED.** The file list is read from
`contracts/shape-pin.yaml` and never re-derived from this repository's copy
lists. An in-place adoption collides on `Makefile`, `README.md` and
`.gitignore`; the shape's copies land under `shape/`, a human merges them and
usually drops the rows. A file with no row is not a shape copy, and re-deriving
the list would resurrect one the project deliberately merged away.
`.gitignore`; the shape's copies land under `shape/`. Once a human merges one
and removes it, `check` calls its row `merged-away` and `apply` drops the row.
A file with no row is no shape copy; re-deriving the list would resurrect it.

**A file the standard ADDS later is the other half, and it is named, never
assumed.** A pin can only record what existed the day it was written, so
Expand Down
11 changes: 6 additions & 5 deletions docs/handbook.html
Original file line number Diff line number Diff line change
Expand Up @@ -1416,8 +1416,8 @@ <h2>Keeping a project&rsquo;s shape current</h2>
<p><code>check</code> prints one verdict per file the pin names, and the verdict is the
product: <code>unchanged</code>, <code>upstream-changed</code> (the bytes differ between the
pinned commit and the target), <code>locally-modified</code> (the project&rsquo;s bytes differ
from the pinned digest &mdash; drift it introduced), <code>both</code> or
<code>already-at-target</code> (the root already holds the target&rsquo;s bytes) &mdash; or,
from the pinned digest &mdash; drift it introduced), <code>both</code>,
<code>already-at-target</code> (the root already holds the target&rsquo;s bytes) or <code>merged-away</code> (below) &mdash; or,
where there is nothing to compare, <code>upstream-removed</code> (the standard no longer has
the file), <code>unmapped</code> (no file there corresponds to it) or
<code>copy-missing</code> (the root has no such file), each of which <code>apply</code>
Expand All @@ -1439,7 +1439,7 @@ <h2>Keeping a project&rsquo;s shape current</h2>
<li><strong>Only the pin&rsquo;s own rows are RE-SYNCED.</strong> The file list is read from
<code>contracts/shape-pin.yaml</code> and never re-derived from this repository&rsquo;s copy
lists &mdash; re-deriving it would resurrect a file the project deliberately merged
away.</li>
away. Once a human merges a <code>shape/</code> copy and removes it, <code>check</code> calls its row <code>merged-away</code> and <code>apply</code> drops the row.</li>
<li>A file the standard ADDS later is reported as <code>upstream-added</code> and counts as
something to do. <code>apply</code> writes NONE of them unless <code>--add &lt;path&gt;</code>
names one, per file; <code>--add</code> refuses a path that is already pinned, one the
Expand Down Expand Up @@ -1879,9 +1879,10 @@ <h2>For AI assistants</h2>
<code>add</code>, <code>bump</code> and <code>remove</code> committing on a branch made first,
never the tracking branch, and printing the push of it, added (#487); the installed doctor
keeping its clone of the standard, which its NEXT lines run from, added (#500); an
adoption&rsquo;s <code>--project</code> as the source&rsquo;s own name, added (#499) &mdash; a
adoption&rsquo;s <code>--project</code> as the source&rsquo;s own name, added (#499); the
<code>merged-away</code> verdict, whose row <code>apply</code> drops, added (#502) &mdash; a
page cannot name the commit that contains it, and the blob below is the fact a test checks.
README.md blob 6bf94d583bb15fc6196c1e0c5232281edc723885. Every command, flag, exit code
README.md blob ae817c5fdb324ff60440b959a15f3ad3b2a18b43. Every command, flag, exit code
and file name on this page is quoted from that README and from AGENTS.md.</p>
</footer>
</main>
Expand Down
10 changes: 10 additions & 0 deletions scripts/shape_materialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,12 @@ def collision_follow_up(intended: str, actual: str,
Where the root's `scripts/bootstrap.py` is the source's own, that command
runs the source's script and exits 0, so the follow-up names no command,
and says both merges come first (#493's review, F2).

AND A PINNED COPY'S FOLLOW-UP SAYS WHAT HAPPENS TO ITS ROW (#502). The
shape pin has a row for a copied file at the path it landed on, so once
the merged copy is removed that row names a file that is not there, and
the project's own `validate-pins.py` is red until `update-shape.py
apply` drops it. A rendered file, `README.md` among them, has no row.
"""
if intended in ASSISTANT_INSTRUCTIONS:
return (
Expand All @@ -692,6 +698,10 @@ def collision_follow_up(intended: str, actual: str,
f"merge {actual} into {intended}: the source repository already has "
"that name, so the shape's copy was written beside it and NOTHING was "
"overwritten")
if intended in COPIED_VERBATIM or any(rel == intended
for _, rel in COPIED_FROM_SHAPE):
merge += (f". Then remove {actual}: `update-shape.py check` reports "
"its pin row `merged-away`, and `apply` drops the row")
if intended != "Makefile":
return merge
targets = ", ".join(f"`{target}`" for target in SHAPE_MAKE_TARGETS)
Expand Down
Loading
Loading