carlos / platform Public

census-propose: Astra round 2 (two P2)

- Census messages are matched to changes by whole key, bounded by a space
  before and a space, semicolon or end after: keys may contain spaces
  ("file.go:type T"), which word-splitting turned into "other" decisions.
- The overlay, card and manifest are written to temp files beside their
  targets and renamed only once all three are on disk, manifest last.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 32cc11ae0e6bdbeabed8d548da065469c5decdfc parent 696024a
2 files changed, +88 −6
  • internal/provision/census_propose_internal_test.go +36 −0
  • internal/provision/census_propose_test.go +52 −6

CI cancelled — superseded by a newer push — run details

CI log
=== gate ===
.amadan/test-gate.sh

amadan: job cancelled — a newer push superseded it

Intent

Human

<task-notification> <task-id>bzl175bpb</task-id> <tool-use-id>toolu_01QDwKtoPjRmo1u49YzW2wW6</tool-use-id> <output-file>/home/paulca/.cache/tmp/claude-1001/-home-paulca-amadan-net-carlos-platform/07894253-fbe8-42e3-8bd7-361304bbebdb/tasks/bzl175bpb.output</output-file> <status>completed</status> <summary>Background command "Run Astra round 2 review" completed (exit code 0)</summary> </task-notification>

Attributed to this commit: 16.9 g CO₂e (2103973 tokens). This is an attribution, not a measurement — usage counted from this commit's own marker forward to the next one on census-approvals, never backward from it. A turn that produced more than one commit books all of its tokens to the last one, and a concurrent session on this branch can add to the same figure. Some of it was priced using the shared default rate, because no model-specific factor row exists yet for at least one model involved. The Carbon view has the repo total, which is never derived from this attribution.

diff --git a/internal/provision/census_propose_internal_test.go b/internal/provision/census_propose_internal_test.go
index 979aea417..19a267956 100644
--- a/internal/provision/census_propose_internal_test.go
+++ b/internal/provision/census_propose_internal_test.go
@@ -335,3 +335,39 @@ func TestCensusProposalRefusesWhatItDidNotWrite(t *testing.T) {
})
}
}
+
+// Keys may contain spaces, and a directory is a prefix of its units' keys.
+func TestCensusNamesWholeKeys(t *testing.T) {
+ for _, tc := range []struct {
+ msg, key string
+ want bool
+ }{
+ {"changed root read internal/h/k.go:type gen; review class", "internal/h/k.go:type gen", true},
+ {"changed legacy declaration internal/h/k.go:type gen", "internal/h/k.go:type gen", true},
+ {"changed root read internal/h/k.go:type general; review", "internal/h/k.go:type gen", false},
+ {"changed root read internal/a/x.go:Foo; review", "internal/a", false},
+ {"changed root source envelope internal/a", "internal/a", true},
+ {"stale root read internal/a/x.go:Foo", "internal/a/x.go:Foo", true},
+ } {
+ if got := censusNames(tc.msg, tc.key); got != tc.want {
+ t.Errorf("censusNames(%q, %q) = %v, want %v", tc.msg, tc.key, got, tc.want)
+ }
+ }
+}
+
+// A body change to a unit whose key has a space is still an approval.
+func TestCensusClassifiesAKeyWithASpace(t *testing.T) {
+ got, inv, seal := proposeFixture(t)
+ key := "internal/a/t.go:type gen"
+ e := classifiedRootRead{rootReadEntry: rootReadEntry{File: "internal/a/t.go", Unit: "type gen", Kinds: "registry:Host@3", Digest: strings.Repeat("7", 64)}, Class: "legacy", Task: "accepted-legacy", Basis: "accepted-legacy;rev3=J1;basis=root-route"}
+ inv.Entries[key], inv.Frozen[key] = e, e
+ inv.Legacy[rootReadLegacyFingerprint(e)] = true
+ seal = rootReadLegacySeal(inv)
+ got.Entries = append(got.Entries, e.rootReadEntry)
+ got.Declarations[key] = e.Digest
+ change(&got, key, "registry:Host@4", strings.Repeat("8", 64))
+ cs := classifyRootReads(got, inv, seal)
+ if len(cs) != 1 || cs[0].Class != censusBody || cs[0].Key != key {
+ t.Fatalf("changes = %+v, want one body for %q", cs, key)
+ }
+}
diff --git a/internal/provision/census_propose_test.go b/internal/provision/census_propose_test.go
index 904af347a..e4ee13494 100644
--- a/internal/provision/census_propose_test.go
+++ b/internal/provision/census_propose_test.go
@@ -178,8 +178,8 @@ func classifyRootReads(got rootReadScan, inv rootReadInventory, seal string) []c
}
for _, msg := range censusDiscrepancies(got, inv, seal) {
explained := false
- for _, tok := range strings.Fields(msg) {
- if keys[strings.TrimRight(tok, ";,")] {
+ for key := range keys {
+ if censusNames(msg, key) {
explained = true
break
}
@@ -197,6 +197,24 @@ func classifyRootReads(got rootReadScan, inv rootReadInventory, seal string) []c
return cs
}
+// censusNames reports whether a census message names key whole: keys may
+// contain spaces ("file.go:type T"), and an envelope's directory is a
+// prefix of its units' keys, so the key must be bounded by a space before
+// it and a space, a semicolon or the end after it (Astra round 2).
+func censusNames(msg, key string) bool {
+ for i := 0; ; {
+ j := strings.Index(msg[i:], " "+key)
+ if j < 0 {
+ return false
+ }
+ end := i + j + 1 + len(key)
+ if end == len(msg) || msg[end] == ' ' || msg[end] == ';' {
+ return true
+ }
+ i += j + 1
+ }
+}
+
// declarationHolds is checkRootReadDeclarations's test for one unit.
func declarationHolds(got rootReadScan, inv rootReadInventory, key string) bool {
frozen, ok := inv.Frozen[key]
@@ -509,12 +527,40 @@ func writeRootReadProposal(root, name string, p rootReadProposal) error {
}
lines = append(lines, file+"\t"+p.Seal)
note := filepath.Join(root, "docs/superpowers/notes", "census-proposal-"+name+".md")
- for _, w := range []struct{ path, text string }{
+ // Every file is written beside its target first and renamed only once
+ // all three are on disk, the manifest last, so a failed write leaves
+ // the previous proposal whole (Astra round 2).
+ writes := []struct{ path, text string }{
{overlay, p.Overlay},
- {manifest, strings.Join(lines, "\n") + "\n"},
{note, p.Card},
- } {
- if err := os.WriteFile(w.path, []byte(w.text), 0o644); err != nil {
+ {manifest, strings.Join(lines, "\n") + "\n"},
+ }
+ var temps []string
+ defer func() {
+ for _, tmp := range temps {
+ os.Remove(tmp)
+ }
+ }()
+ for _, w := range writes {
+ f, err := os.CreateTemp(filepath.Dir(w.path), "."+filepath.Base(w.path)+".*")
+ if err != nil {
+ return err
+ }
+ temps = append(temps, f.Name())
+ if _, err := f.WriteString(w.text); err != nil {
+ f.Close()
+ return err
+ }
+ if err := f.Chmod(0o644); err != nil {
+ f.Close()
+ return err
+ }
+ if err := f.Close(); err != nil {
+ return err
+ }
+ }
+ for i, w := range writes {
+ if err := os.Rename(temps[i], w.path); err != nil {
return err
}
}