Skip to content

Round 33 — backlog scope audit + GOVERNANCE §29#12

Merged
AceHack merged 1 commit intomainfrom
round-33-backlog-audit
Apr 19, 2026
Merged

Round 33 — backlog scope audit + GOVERNANCE §29#12
AceHack merged 1 commit intomainfrom
round-33-backlog-audit

Conversation

@AceHack
Copy link
Copy Markdown
Member

@AceHack AceHack commented Apr 19, 2026

Aaron caught a factory drift this round: I'd been dumping non-security items (openspec-gap-finder, static-analysis-gap-finder, declarative-manifest, post-install automation research, documentation-agent cadence, devcontainer, Windows CI) into SECURITY-BACKLOG.md. None of those are security controls.

Changes

  • 8 items moved SECURITY-BACKLOG → BACKLOG. Plus 3 new round-33 items added to BACKLOG (upstream sync script, upstream-comparative-analysis skill, upstream categorisation audit).
  • SECURITY-BACKLOG retains only security controls: side-channel, constant-time, TEE, SLSA, HSM, pen-test, DAST, repro builds, compliance certs, mise-trust, verifier SHA-pin, safety-clause diff, signed commits, NuGet prefix.
  • GOVERNANCE §29 binding rule: "Backlog files are scoped." backlog-scrum-master owns enforcement cadence. Test: "would an external security auditor expect to see this entry?" → if no, it's BACKLOG.md.

🤖 Generated with Claude Code

Aaron caught a factory drift: I'd been dumping non-security
items (static-analysis-gap-finder, declarative-manifest,
post-install automation, documentation-agent cadence, etc.)
into SECURITY-BACKLOG. None of those are security controls.
Aaron: "why is this [Bun+TS entry] in security backlog that
weird? Is this just not regular backlog? Should we do a
security backlog audit to make sure it's only security items
and vice versa. How do we stop this from happening in the
factory in the future if this is an issue."

Changes:

1. Moved 8 non-security items from SECURITY-BACKLOG.md to
   docs/BACKLOG.md under a new "P1 — Factory / static-analysis
   / tooling (round-33 surface)" section:
   - openspec-gap-finder skill
   - static-analysis-gap-finder skill
   - Crank lint configs to HIGH
   - documentation-agent cadence
   - Declarative-manifest setup (scratch shape)
   - Post-install repo automation (runtime research)
   - Devcontainer / Codespaces image
   - Windows CI matrix
   Also added two new items from this round's conversation:
   - Upstream sync script + references/upstreams/ population
   - upstream-comparative-analysis skill
   - Upstream categorisation audit (multi-round)

2. SECURITY-BACKLOG.md retains only genuine security controls
   (hardware side-channel, constant-time, TEE, SLSA, HSM,
   pen-test, DAST, reproducible builds, compliance certs,
   mise-trust hardening, verifier-jar SHA-pin, safety-clause
   diff, signed-commits, NuGet prefix). Comment placeholder
   marks the migration for future readers.

3. **GOVERNANCE §29** — new binding rule: "Backlog files are
   scoped." BACKLOG.md = general engineering / factory / tooling.
   SECURITY-BACKLOG.md = security controls only (feeds SDL
   attestations + threat-model reviews). Cross-contamination is
   a smell. `backlog-scrum-master` owns enforcement cadence.
   Rule of thumb: "would an external security auditor expect
   to see this entry?" — if no, it goes in BACKLOG.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@AceHack AceHack merged commit 7e731bf into main Apr 19, 2026
6 checks passed
@AceHack AceHack deleted the round-33-backlog-audit branch April 19, 2026 03:09
AceHack referenced this pull request in AceHack/Zeta Apr 21, 2026
Three resonance-research-track rows filed in real chronological
order (mythology P2 → occult P2 → AI-ethics-and-safety P1 with
explicit "filed LATER" annotation preserving Aaron's self-
correction "whoops we should have done that first"):

- **Mythology** (P2, seed Heimdallr candidate #12 bridge-figure;
  wider candidates Hermes/Mercury, Janus, Iris, Ratatoskr, Thoth,
  Garuda, Quetzalcoatl; Loki flagged as anti-instance).
- **Occult / Western-esoteric** (P2, seed Crowley with honest
  three-filter pass showing F1 pass / F2 weak at whole-person /
  F3 cross-tradition weak; wider candidates Hermeticism,
  Kabbalah/Lurianic tzimtzum, Enochian, Levi, Agrippa, Golden
  Dawn, Theosophy, Jungian alchemy).
- **AI ethics + safety** (P1, coordinates with Nazar/Aminata/
  Mateo/Nadia as horizontal log-and-retractibility check; owner
  Sova; Architect integrates; Aaron signs off; L effort;
  substrate-foundational but no ship-block hence P1 not P0).

All three rows use retractibility-math safety framing per
`feedback_no_permanent_harm_mathematical_safety_retractibility_preservation.md` —
prose hedges ("NOT endorsement / cultural-appropriation / NOT
public-facing") dropped, replaced with retractibility-preserving
constraints only (no force-push, no unbacked-up memory deletion,
no public-release ship without Aaron sign-off).

Pure additive edit (420 insertions, 0 deletions) — chess-check
verified no time-travel. Preserves real order of events per
`feedback_preserve_real_order_of_events_dont_retroactively_reorder_by_priority.md`.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
AceHack referenced this pull request in AceHack/Zeta Apr 21, 2026
Two changes in one commit:

1. Fix markdownlint MD029 ship-blocker on PR Lucent-Financial-Group#54: flags previously
   labeled 11 and 12 in the Frontier edge-claims list were actually
   the 10th and 11th items. Renumbered 11→10 (pyromid) and 12→11
   (factory-IS-the-experiment) + updated two "flag #11" cross-
   references in flag #5 to "flag #10". Local markdownlint clean.

2. Plant new CTF flag #12: Teaching is how we change the current
   order — chronology, everything, * (the retractibility-preserving
   mechanism of change). Aaron 2026-04-21 four-message compression
   naming TEACHING as the retractibility-preserving method of change
   with totalizing scope (temporal → universal → wildcard). Teaching
   is the SEMANTICS; retractibly-rewrite is the ALGEBRA. Defense
   surface cites Khan Academy as canonical civilizational-scale
   substrate-evidence per Aaron "I love Mr Khan" follow-up — mission
   "Free, world-class education for anyone, anywhere" literally
   instantiates the * wildcard applied to education access with
   measurable 100M+ learner time-series.

Pure additive edit; no history rewrite; retractibility preserved.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
AceHack added a commit that referenced this pull request Apr 24, 2026
…59 (Amara Determinize action) (#225)

Amara's 4th ferry (PR #221 absorb) Determinize-stage item:
prevent the retrieval-drift class where prose cites paths that
don't resolve. Her commit samples show repeated cleanup passes
for memory paths that didn't exist; this is the third leg of
memory-index hygiene.

Three-leg memory-index hygiene now complete:

  1. row #58 (PR #220 merged) — every memory/*.md change
     updates MEMORY.md in same commit/PR
  2. AceHack PR #12 (pending Aaron merge) — MEMORY.md has
     no duplicate link targets
  3. row #59 (this PR) — every MEMORY.md link target
     resolves to an actual file under memory/

New artifacts:

- tools/hygiene/audit-memory-references.sh
  Parses `](foo.md)` link targets, resolves each against
  base dir (default memory/), fails (exit 2 under --enforce)
  on any broken reference. Supports --file PATH + --base DIR
  for custom use.

- .github/workflows/memory-reference-existence-lint.yml
  Safe-pattern compliant per FACTORY-HYGIENE row #43
  (SHA-pinned checkout, minimum permissions, concurrency
  group, runs-on pinned, no user-authored context).
  Triggers on PRs/pushes touching memory/** or the audit
  tool / workflow itself.

- FACTORY-HYGIENE row #59 documenting cadence / owner /
  scope / classification (prevention-bearing — blocks
  merge before broken refs land).

First-run baseline captured in commit:

- In-repo memory/MEMORY.md: 44 refs all resolve (clean)
- Per-user MEMORY.md: 391 refs all resolve (clean)

Both clean confirms that PR #220's memory-index-integrity CI
has been keeping the substrate in good shape. This lint
closes the third-leg gap before drift regresses.

Amara Determinize-stage progress: 2/5 (with this PR).
  ✓ Live-state-before-policy (PR #224)
  ✓ Memory reference-existence lint (this PR)
  Remaining:
  - Memory duplicate-title lint (partial via AceHack PR #12)
  - Generated CURRENT-*.md views (L)
  - Memory reconciliation algorithm (L)

Per Aaron Otto-72 standing directive: acting under Otto-67
full-GitHub authority, decisions logged in PR body + memory,
Frontier UI is the future batch-review surface.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
AceHack added a commit that referenced this pull request Apr 24, 2026
…ase, audit fail-hard, endpoint lists

Drains 14 unresolved review threads on PR #147 (FactoryDemo.Api.CSharp):
- Zeta.sln: strip leading blank line so 'Microsoft Visual Studio
  Solution File' is the first line (threads #2 #3).
- SignalQuality.fs: compressionRatio on empty input was 1.0, which
  composed as Quarantine via severityOfScore — flipped to 0.0 and
  added explicit empty-input Pass finding in compressionMeasure;
  also dropped unused System.Runtime.CompilerServices open
  (threads #4 #5).
- live-lock-audit.sh: fail hard (exit 2) when origin/main is not
  resolvable so a missing-remote CI checkout can't silently report
  'No commits found' -> healthy; switched --stat|awk file-list
  extraction to git diff-tree --name-only plumbing form
  (threads #1 #6).
- ServiceTitanFactoryApi README + Seed.fs: remove dead memory/
  and docs/plans/ links; replace Aaron's-name reference with
  'human maintainer' role wording; drop non-existent sibling
  SQL-seed refs (threads #7 #8 #9).
- FactoryDemo.Api.CSharp README + Program.cs + Seed.cs: fix dead
  refs to samples/FactoryDemo.Api.FSharp/ and samples/FactoryDemo.Db/
  to point at the real F# sibling samples/ServiceTitanFactoryApi/
  and to a BACKLOG row for the Postgres-backed follow-up
  (threads #11 #14).
- Program.cs + Program.fs: root endpoint index now advertises all
  9 routes including the parameterised {id} routes, matching the
  README tables (threads #12 #13).
- Thread #10 (project naming 'ServiceTitanFactoryApi.CSharp' in PR
  description): resolved in-thread — code/namespace already
  consistent (Zeta.Samples.FactoryDemo.Api); fix is PR-description-
  only, not code.

Build: dotnet build -c Release -> 0 Warning(s) 0 Error(s).
AceHack added a commit that referenced this pull request Apr 24, 2026
…ase, audit fail-hard, endpoint lists

Drains 14 unresolved review threads on PR #147 (FactoryDemo.Api.CSharp):
- Zeta.sln: strip leading blank line so 'Microsoft Visual Studio
  Solution File' is the first line (threads #2 #3).
- SignalQuality.fs: compressionRatio on empty input was 1.0, which
  composed as Quarantine via severityOfScore — flipped to 0.0 and
  added explicit empty-input Pass finding in compressionMeasure;
  also dropped unused System.Runtime.CompilerServices open
  (threads #4 #5).
- live-lock-audit.sh: fail hard (exit 2) when origin/main is not
  resolvable so a missing-remote CI checkout can't silently report
  'No commits found' -> healthy; switched --stat|awk file-list
  extraction to git diff-tree --name-only plumbing form
  (threads #1 #6).
- ServiceTitanFactoryApi README + Seed.fs: remove dead memory/
  and docs/plans/ links; replace Aaron's-name reference with
  'human maintainer' role wording; drop non-existent sibling
  SQL-seed refs (threads #7 #8 #9).
- FactoryDemo.Api.CSharp README + Program.cs + Seed.cs: fix dead
  refs to samples/FactoryDemo.Api.FSharp/ and samples/FactoryDemo.Db/
  to point at the real F# sibling samples/ServiceTitanFactoryApi/
  and to a BACKLOG row for the Postgres-backed follow-up
  (threads #11 #14).
- Program.cs + Program.fs: root endpoint index now advertises all
  9 routes including the parameterised {id} routes, matching the
  README tables (threads #12 #13).
- Thread #10 (project naming 'ServiceTitanFactoryApi.CSharp' in PR
  description): resolved in-thread — code/namespace already
  consistent (Zeta.Samples.FactoryDemo.Api); fix is PR-description-
  only, not code.

Build: dotnet build -c Release -> 0 Warning(s) 0 Error(s).
AceHack added a commit that referenced this pull request Apr 24, 2026
…ase, audit fail-hard, endpoint lists

Drains 14 unresolved review threads on PR #147 (FactoryDemo.Api.CSharp):
- Zeta.sln: strip leading blank line so 'Microsoft Visual Studio
  Solution File' is the first line (threads #2 #3).
- SignalQuality.fs: compressionRatio on empty input was 1.0, which
  composed as Quarantine via severityOfScore — flipped to 0.0 and
  added explicit empty-input Pass finding in compressionMeasure;
  also dropped unused System.Runtime.CompilerServices open
  (threads #4 #5).
- live-lock-audit.sh: fail hard (exit 2) when origin/main is not
  resolvable so a missing-remote CI checkout can't silently report
  'No commits found' -> healthy; switched --stat|awk file-list
  extraction to git diff-tree --name-only plumbing form
  (threads #1 #6).
- ServiceTitanFactoryApi README + Seed.fs: remove dead memory/
  and docs/plans/ links; replace Aaron's-name reference with
  'human maintainer' role wording; drop non-existent sibling
  SQL-seed refs (threads #7 #8 #9).
- FactoryDemo.Api.CSharp README + Program.cs + Seed.cs: fix dead
  refs to samples/FactoryDemo.Api.FSharp/ and samples/FactoryDemo.Db/
  to point at the real F# sibling samples/ServiceTitanFactoryApi/
  and to a BACKLOG row for the Postgres-backed follow-up
  (threads #11 #14).
- Program.cs + Program.fs: root endpoint index now advertises all
  9 routes including the parameterised {id} routes, matching the
  README tables (threads #12 #13).
- Thread #10 (project naming 'ServiceTitanFactoryApi.CSharp' in PR
  description): resolved in-thread — code/namespace already
  consistent (Zeta.Samples.FactoryDemo.Api); fix is PR-description-
  only, not code.

Build: dotnet build -c Release -> 0 Warning(s) 0 Error(s).
AceHack added a commit that referenced this pull request Apr 24, 2026
…sibling (#147)

* Live-lock audit history: inaugural lesson integrated — prevention discipline for next time

Aaron 2026-04-23:

> if you want to beat ARC3 and do better than humans at uptime and
> other DORA metrics then your live-lock smell and the decisions you
> make to prevent live locks in the future based on pass lessons, the
> ability to integrate previous lessions and not forget is ging to be
> key.

Lesson-permanence is the factory's competitive differentiator.
Detection (audit script) is table stakes. Integration — recording the
lesson, consulting it forward, preventing re-occurrence — is the
product.

## What lands

- New "Lessons integrated" section in
  `docs/hygiene-history/live-lock-audit-history.md`
- Inaugural lesson from tonight's smell-firing event, structured as
  signature / mechanism / prevention with 4 concrete prevention
  decisions:
  1. External-priority stack is authoritative; agent reorders only
     internal priorities
  2. Live-lock audit at round-close is a gate-not-a-report
  3. Speculative-work permit requires external-ratio check first
  4. Tick-history rows are explicitly NOT external work; pair INTL
     with EXT when the smell is near firing
- Open carry-forward named: round-close-ladder wiring is a P1
  follow-up (BACKLOG row already filed earlier this session)

## Discipline

Every future smell firing files a lesson to this same section.
`memory/feedback_lesson_permanence_is_how_we_beat_arc3_and_dora_2026_04_23.md`
captures the full rule: detection is not enough, integration is the
product, lessons are consulted BEFORE taking actions that match known
failure-mode signatures, memory persists across sessions.

The pattern extends beyond live-lock: other detection mechanisms
(SignalQuality firing, Amara-oracle rejecting, drift-tick exceeding
threshold, OpenSpec Viktor failing rebuild-from-spec) should file
lessons to their respective hygiene-history files.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* samples: ServiceTitan factory-demo JSON API (v0, in-memory, stack-independent)

Minimal F# ASP.NET Core Web API serving CRM seed data as JSON. Any
frontend choice (Blazor / React / Vue / curl) consumes the same
endpoints. Ships now so the backend is not on the critical path when
Aaron picks the frontend stack.

## What lands

- `samples/ServiceTitanFactoryApi/ServiceTitanFactoryApi.fsproj`
  using `Microsoft.NET.Sdk.Web`; only explicit package ref is
  `FSharp.Core` (ASP.NET Core comes via framework reference, no
  Directory.Packages.props edit needed)
- `Seed.fs` — in-memory seed mirroring `ServiceTitanFactoryDemo/seed-data.sql`:
  20 customers, 30 opportunities (5 stages), 33 activities, 2 intentional
  email collisions. Deterministic fixed clock at 2026-04-23 00:00 UTC.
- `Program.fs` — minimal F# API with 9 endpoints: customers (list/detail),
  opportunities (list/detail), activities (list/per-customer), pipeline
  funnel (count + total-cents per stage), duplicates (customers sharing
  an email).
- `README.md` — framing (software-factory demo, not database pitch),
  endpoint table, design notes, v1 roadmap.

## Smoke-test output (verified)

```
GET /api/pipeline/funnel
[{"count":10,"stage":"Lead","totalCents":5400000},
 {"count":6, "stage":"Qualified","totalCents":4220000},
 {"count":6, "stage":"Proposal","totalCents":5720000},
 {"count":6, "stage":"Won","totalCents":2670000},
 {"count":2, "stage":"Lost","totalCents":490000}]

GET /api/pipeline/duplicates
[{"customerIds":[1,13],"email":"alice@acme.example"},
 {"customerIds":[5,19],"email":"bob@trades.example"}]
```

Build: 0 Warning(s), 0 Error(s). `dotnet run` starts the API;
curl confirms all endpoints respond correctly.

## Discipline signal

This is the third EXT commit of the session (CRM demo sample #141,
CRM scenario tests in #143, now this API). The live-lock audit's
inaugural lesson explicitly prescribed shipping external-priority
increments when the smell fires. Three landed this session, all on
priority #1 (ServiceTitan + UI) — the factory is correctly
response-pattern even before any of tonight's PRs merge to main.

## What this does NOT do

- Does NOT wire Postgres — in-memory only for v0; Npgsql wiring is
  a follow-up PR once Aaron confirms the DB driver
- Does NOT expose Zeta / DBSP / retraction-native language to the
  frontend — standard CRUD shape per the ServiceTitan positioning
  directive
- Does NOT implement writes — v0 is read-only; POST/PUT/DELETE is
  a follow-up
- Does NOT add auth — no authentication for v0
- Does NOT ship docker-compose — future PR bundles this API with
  Postgres in one command

Composes with:
- `samples/ServiceTitanFactoryDemo/` (SQL schema + seed) — sibling,
  same shapes; v1 wires this API to that schema
- `docs/plans/servicetitan-crm-ui-scope.md` — build sequence step 1
  (API skeleton) complete; step 2 (DB wiring) is next
- `memory/feedback_servicetitan_demo_sells_software_factory_not_zeta_database_2026_04_23.md`
- `memory/feedback_lesson_permanence_is_how_we_beat_arc3_and_dora_2026_04_23.md`

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* samples: ServiceTitan factory-demo C# companion API — parity with F# sibling

ServiceTitan uses C# for most of their backend with zero F#. Shipping
a C# companion to the F# API (#146) so ST engineers evaluating the
factory see code in the language they already read fluently.
F# stays the reference — it's closer to math, theorems are easier to
express — but factory output matches audience stack.

## What lands

- `ServiceTitanFactoryApi.CSharp.csproj` — `Microsoft.NET.Sdk.Web`,
  nullable + implicit usings enabled, TreatWarningsAsErrors
- `Customer.cs`, `Opportunity.cs`, `Activity.cs` — records, one
  per file (MA0048)
- `Seed.cs` — deterministic in-memory seed, identical to F# Seed.fs:
  20 customers, 30 opportunities, 33 activities, 2 intentional
  email collisions
- `Program.cs` — 9 minimal-API endpoints, identical routes + JSON
  shapes to the F# sibling
- `README.md` — parity guarantee, design notes, C# specifics

## Smoke-test parity (verified)

```
GET /api/pipeline/funnel
[{"stage":"Lead","count":10,"totalCents":5400000}, ...5 stages]

GET /api/pipeline/duplicates
[{"email":"alice@acme.example","customerIds":[1,13]},
 {"email":"bob@trades.example","customerIds":[5,19]}]

GET /api/customers  -> 20 customers
```

Same seed, same shapes, same numbers as the F# version (#146).
Frontends switch between them without code changes.

## Analyzer discipline passes

Build: 0 Warning(s), 0 Error(s) with the full SonarAnalyzer.CSharp +
Meziantou.Analyzer + Microsoft .NET Analyzers pack active. The C#
companion respects every rule the F# version's discipline
already encodes implicitly — StringComparer.Ordinal for GroupBy,
static-readonly for endpoint list, record-per-file, no-var-discarded.

## Discipline signal

Fourth EXT commit of the session (CRM demo #141, CRM scenario tests
#143, F# API #146, now this C# API). All on Aaron's priority #1.
The live-lock audit's inaugural lesson prescribed "ship external-
priority increments when smell fires" — four landed in one session.

## Factory-pitch moment

This pair (F# + C# from the same spec, identical behaviour) is a
concrete factory-capability signal. The software factory produces
code in your stack, to your analyzer discipline, with parity across
languages. The pitch isn't "pick our language"; it's "your language,
enforced by our quality floor."

## What this does NOT do

- Does NOT rewrite or deprecate the F# sibling — both live
- Does NOT wire Postgres — same v0 scope
- Does NOT leak Zeta / DBSP / retraction-native concepts to the
  ST-facing surface
- Does NOT claim the C# version is the primary — F# is reference

Composes with:
- `samples/ServiceTitanFactoryApi/` (F# sibling)
- `memory/project_zeta_f_sharp_reference_c_sharp_and_rust_future_servicetitan_uses_csharp_2026_04_23.md`
- `memory/feedback_servicetitan_demo_sells_software_factory_not_zeta_database_2026_04_23.md`

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* rename: generic FactoryDemo.Api.CSharp (was ServiceTitanFactoryApi.CSharp)

Aaron 2026-04-23 directive:

> lets try to reduce the number of class and thing we call servce titan
> or this will be confusing in a Zeta repo. ... this is not a service
> titan repo, it's an open source repo.

Plus, 2026-04-23 follow-up on language priority:

> c# is a more popular language than f# so it makes sense to start
> with a factory c# demo anyways

## What renames

- `samples/ServiceTitanFactoryApi.CSharp/` →
  `samples/FactoryDemo.Api.CSharp/`
- Project name + csproj filename same rename
- `RootNamespace` `Zeta.Samples.ServiceTitanFactoryApi` →
  `Zeta.Samples.FactoryDemo.Api`
- `namespace` declarations in .cs files match
- Zeta.sln project entry updated
- README rewritten to generic framing (C# is the popular
  .NET language; demo starts there; F# stays reference)
- Root endpoint name field `"ServiceTitan factory-demo API (C#)"` →
  `"Factory-demo API (C#)"`
- All doc cross-references updated to new path names

Build: 0 Warning(s), 0 Error(s) with the full SonarAnalyzer +
Meziantou + Microsoft .NET Analyzers pack. Behaviour unchanged —
same 9 endpoints, same JSON shapes, same seed.

Memory rule:
`memory/feedback_open_source_repo_demos_stay_generic_not_company_specific_2026_04_23.md`
captures the positioning directive in durable form so future
agents don't re-introduce company-specific names.

Sibling renames land in separate PRs / branches:
- F# API sibling (currently PR #146 / ServiceTitanFactoryApi)
- DB scaffold (PR #145 / ServiceTitanFactoryDemo)
- CRM kernel sample (PR #141 / ServiceTitanCrm)
- CRM-UI scope doc (PR #144 / docs/plans/servicetitan-crm-ui-scope.md)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* FactoryDemo.Api.CSharp: smoke-test.sh — end-to-end endpoint + contract verification

I chose to land this because the JSON-shape parity claim we make
in the README ("byte-identical shapes between F# and C# versions")
needs a machine-verifiable check. A smoke test on the C# side is the
first half; the F# sibling gets the same pattern in a follow-up.

Starts the API on a random port, waits up to 10s for readiness,
then runs 19 checks against all 9 endpoints:

  - Root metadata: name, version, endpoints length
  - Collection lengths: customers (20), opportunities (30), activities (33)
  - Single-item lookup: customer #1 name, opportunity #1 stage
  - Per-customer activities: customer #1 has 4
  - Pipeline funnel counts per stage: Lead 10, Qualified 6, Won 6, Lost 2
  - Pipeline funnel totals in cents: Lead $54k, Won $26.7k
  - Duplicates: 2 pairs, (1,13) share alice@acme, (5,19) share bob@trades
  - 404 behaviour: missing customer returns 404

Shuts the API down cleanly on exit via trap + kill.

```
$ bash samples/FactoryDemo.Api.CSharp/smoke-test.sh
Building API...
Starting API on http://localhost:5235...

Factory-demo C# API smoke test
==============================
  OK   root.name contains 'Factory-demo'                  (true)
  OK   root.version                                       (0.0.1)
  OK   root.endpoints length                              (5)
  OK   /api/customers length                              (20)
  ...
  OK   missing customer HTTP status                       (404)

All checks passed.
```

dotnet, curl, jq — all standard dev tools. The demo does not ask
for anything exotic. Matches the FactoryDemo.Db smoke-test.sh
pattern on the sibling branch.

- Random high port (5100-5499) instead of fixed — reduces collision
  with other dev services.
- `curl -sf` for normal checks, `curl -o /dev/null -w "%{http_code}"`
  for the 404 case — the two paths have different error semantics so
  I use different tools for each.
- Shape-level assertions against numeric counts rather than raw JSON
  diff — makes the test tolerant of property-ordering differences
  between serializers. The parity claim is about *shape*, not byte-
  identity, so this matches intent.
- Trap + kill on EXIT — guarantees the API stops even on test
  failure or ctrl-C. No leaked background processes.

- Does NOT test the F# sibling. Same-pattern smoke-test for
  FactoryDemo.Api.FSharp lands in its branch (or a follow-up
  PR on that branch).
- Does NOT diff F# vs C# outputs directly. A cross-language
  parity-diff test composes better as a separate tool once both
  APIs have merged.
- Does NOT wire to Postgres. In-memory seed only; docker-compose
  + DB wiring is a separate PR.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* samples+audit: PR #147 review-drain — sln BOM, signal-quality empty-case, audit fail-hard, endpoint lists

Drains 14 unresolved review threads on PR #147 (FactoryDemo.Api.CSharp):
- Zeta.sln: strip leading blank line so 'Microsoft Visual Studio
  Solution File' is the first line (threads #2 #3).
- SignalQuality.fs: compressionRatio on empty input was 1.0, which
  composed as Quarantine via severityOfScore — flipped to 0.0 and
  added explicit empty-input Pass finding in compressionMeasure;
  also dropped unused System.Runtime.CompilerServices open
  (threads #4 #5).
- live-lock-audit.sh: fail hard (exit 2) when origin/main is not
  resolvable so a missing-remote CI checkout can't silently report
  'No commits found' -> healthy; switched --stat|awk file-list
  extraction to git diff-tree --name-only plumbing form
  (threads #1 #6).
- ServiceTitanFactoryApi README + Seed.fs: remove dead memory/
  and docs/plans/ links; replace Aaron's-name reference with
  'human maintainer' role wording; drop non-existent sibling
  SQL-seed refs (threads #7 #8 #9).
- FactoryDemo.Api.CSharp README + Program.cs + Seed.cs: fix dead
  refs to samples/FactoryDemo.Api.FSharp/ and samples/FactoryDemo.Db/
  to point at the real F# sibling samples/ServiceTitanFactoryApi/
  and to a BACKLOG row for the Postgres-backed follow-up
  (threads #11 #14).
- Program.cs + Program.fs: root endpoint index now advertises all
  9 routes including the parameterised {id} routes, matching the
  README tables (threads #12 #13).
- Thread #10 (project naming 'ServiceTitanFactoryApi.CSharp' in PR
  description): resolved in-thread — code/namespace already
  consistent (Zeta.Samples.FactoryDemo.Api); fix is PR-description-
  only, not code.

Build: dotnet build -c Release -> 0 Warning(s) 0 Error(s).

* drain PR #147: post-rebase thread fixes — test-empty-ratio + smoke-endpoint-count

- tests/Tests.FSharp/Algebra/SignalQuality.Tests.fs: test asserted 1.0 for
  compressionRatio on empty input, but the fix in 16ad746 changed the
  convention to 0.0 (neutral = clean, not maximally suspicious). Updated
  the test expectation + name + comment to match the current code.
- samples/FactoryDemo.Api.CSharp/smoke-test.sh: root.endpoints length
  expectation was 5; Program.cs now advertises 8 routes in the index
  (post 16ad746 expansion). Corrected the smoke-test assertion.

Rebased onto origin/main (which advanced via #146 FactoryDemo.Api.FSharp
merge); Zeta.sln conflicts resolved by keeping both FactoryDemo.Api.FSharp
and the ServiceTitanCrm/samples solution-folder additions.

Build gate: 0 Warning(s) / 0 Error(s) in Release.

* PR #147 review-drain — Copilot pass on b4f5a49

Addresses five unresolved review threads:

- drop/README.md: sweep name attribution to "the human
  maintainer" role-ref (BP-name-attribution).
- samples/FactoryDemo.Api.CSharp/Program.cs: fix endpoint
  comment "9 concrete endpoints" → "8 API endpoints besides
  `/`" (array has 8; root excluded).
- samples/FactoryDemo.Api.CSharp/smoke-test.sh: per-run log
  via mktemp (collision-safe + non-/tmp-host-safe); print
  path on failure + success.
- samples/ServiceTitanFactoryApi/: delete stale F# sibling
  dir (PR #146 already landed FactoryDemo.Api.FSharp on
  main with identical code); drop duplicate sln Project
  block + config duplicates; fix CSharp refs to point at
  the surviving FactoryDemo.Api.FSharp/.

Fifth thread (SignalQuality scope-creep) is judgment —
branch history is deep; splitting now adds more churn than
value. Replying with backlog-and-resolve per three-outcome.

* PR #147 review-drain — 7 threads (Copilot + Codex)

Threads drained:
- btw.md: name attribution -> "human maintainer" / "the maintainer" (Copilot P1, AGENT-BEST-PRACTICES.md:284-292)
- live-lock-audit.sh: add --root to git diff-tree so root commit classifies correctly (Copilot P2)
- FactoryDemo.Api.CSharp Program.cs: add "/" to endpoints list for F# parity; bump smoke-test length 8->9 (Copilot P1 + Codex P2, same fix)
- FactoryDemo.Api.CSharp smoke-test.sh: reword mktemp comment to describe system temp dir accurately (Copilot P2)
- ServiceTitanCrm -> FactoryDemo.Crm: rename dir, fsproj, module namespace, RootNamespace, sln entry, test doc-comment; drop stale ServiceTitanFactoryApi bin+obj (Copilot P1, memory/feedback_open_source_repo_demos_stay_generic_not_company_specific_2026_04_23.md:59-66)
- SignalQuality.fs: compressionRatio + compressionMeasure short-circuit to 0.0 (Pass) below 64-byte threshold to avoid gzip-header-dominates Quarantine of legitimate short strings (Codex P1)

Drain log: docs/pr-preservation/147-drain-log.md preserves each thread verbatim (git-native high-signal preservation).

dotnet build -c Release: 0 Warning(s), 0 Error(s).

* PR #147 review-drain second pass — 4 fix-inline + 3 scope-bleed

- Seed.cs + Seed.fs: rename contact 13 'Aaron Smith' -> 'Acme Contact
  (new lead)' (Copilot P2 name-attribution, parity preserved across
  C# / F# siblings).
- drop/README.md: correct 'only tracked file' wording to reflect the
  README.md + .gitignore two-sentinel design (Copilot P2).
- tools/audit/live-lock-audit.sh: docstring attribution 'Aaron's ...'
  -> 'Human-maintainer ...' (Copilot P1); add '-m' plus 'sort -u' to
  'git diff-tree' so merge commits bucket on their real files instead
  of mis-classifying as OTHR (Codex P1 — was skewing EXT/INTL/SPEC %
  and could disable the live-lock gate after a round of merges).
- docs/pr-preservation/147-drain-log.md: append second-pass per-thread
  audit trail (git-native preservation).

Three threads resolved as scope-bleed / already-addressed: operator-
input-quality-log.md (file not in PR diff, landed via 204bbb6 on
main), AUTONOMOUS-LOOP.md (file not in PR diff, zero Aaron on HEAD),
Tests.FSharp.fsproj (both SignalQuality + CrmScenarios already listed
at lines 26 and 49).

Build: 0W/0E. Audit sanity: live-lock-audit.sh still healthy with
merges now bucketed correctly.

* fix: markdownlint MD001/MD022/MD032 on #147 drain-log (h3→h2 on Thread headers)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* drain: resolve 11 threads on #147 (mix FIX + BACKLOG + Otto-256 reject)

Thread-by-thread outcomes across the 11 unresolved review threads on PR
#147 (5 FIX, 2 BACKLOG, 2 Otto-256 REJECT, 2 already-addressed/stale):

FIXES (code):
- live-lock-audit.sh: replace `git show --stat` with explicit
  `git log -1 -m --first-parent --name-only` so merge commits classify
  against parent-1 only (the landing side). The prior `git show` form
  risked combined-diff semantics in some git versions; the explicit
  form is first-parent by construction (Codex P1).
- SignalQuality.fs: restore `compressionMinInputBytes = 64` threshold
  (dropped by the f1dc2bb merge-conflict resolution) and mark it
  `private` so it is not part of the public API surface (Copilot).
  Short-circuits `compressionRatio` + `compressionMeasure` to 0.0 for
  sub-threshold inputs, avoiding spurious Quarantine on short legitimate
  strings. Evidence reports UTF-8 byte count (consistent with the
  threshold's units) instead of `text.Length` chars (Copilot). Adjusted
  the empty-string test to assert the new 0.0 neutral value.
- smoke-test.sh: replace non-portable `mktemp -t <template>` with a
  pre-constructed absolute-path template rooted at `${TMPDIR:-/tmp}`
  where XXXXXX is the tail (BSD/macOS requires tail-XXXXXX; GNU accepts
  either). `.log` extension is appended via `mv` after creation so the
  single invocation is cross-platform (Copilot x2 — threads 4 + 10).
- CrmScenarios.Tests.fs: update doc-comment `samples/FactoryDemo.Crm`
  -> `samples/CrmSample` to match the canonical sample path on main
  (Copilot).

BACKLOG (deferred P2):
- Smoke-test deterministic port allocation (Codex P2) — replace
  RANDOM-in-range with OS-assigned ephemeral port via `--urls
  http://127.0.0.1:0` and log-line parse.
- FactoryDemo.Api.CSharp solution project-type GUID hygiene (Copilot)
  — align with modern SDK-style GUID used by other C# projects.

OTTO-256 REJECT (history-file exemption):
- docs/pr-preservation/147-drain-log.md (Copilot) and
  docs/hygiene-history/live-lock-audit-history.md (Copilot): both
  requested stripping first-name "Aaron" attributions. Declined per
  Otto-256 (2026-04-24) — history files exempt from the "no name
  attribution" rule; a P2 BACKLOG row already exists
  (`## P2 — FACTORY-HYGIENE — name-attribution policy clarification
  (history-file exemption)`) to codify this in AGENT-BEST-PRACTICES.md.

ALREADY-ADDRESSED (stale reviewer context):
- drop/README.md heading (Copilot): Copilot flagged "one tracked
  sentinel" but the current heading reads "two tracked sentinels"
  (fixed in a prior drain). Resolving as addressed.

Build: `dotnet build -c Release` -> 0 Warning(s), 0 Error(s).
Tests: `dotnet test --filter "FullyQualifiedName~SignalQuality"` ->
  22/22 pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
AceHack added a commit that referenced this pull request Apr 25, 2026
…gment

Two Codex post-merge findings on PR #430:

(line 72) — table contains in-flight row not covered by
'BACKLOG candidates' framing:
The intro said the table is BACKLOG candidates spanning
P1-P3, but Memory duplicate-title lint is tagged 'in-flight'
(landed elsewhere via PR #12). Updated intro to note the
in-flight row explicitly: 'BACKLOG candidates spanning P1,
P2, and P3 sections plus one in-flight row tracking work
that already landed elsewhere'.

(line 400) — orphaned line wrap:
'are the' was on its own line as a wrap artifact, making the
sentence harder to read. Reflowed so 'right next tick or two'
joins the prior line.
AceHack added a commit that referenced this pull request Apr 25, 2026
… claim soften (#430)

* drain(#221 follow-up Codex): terminology + count alignment + 'preserved' soften

Five Codex post-merge findings on the merged Amara memory-drift absorb:

1. decision-proxy-consult vs decision-proxy-evidence (line 282):
   Risk matrix used 'decision-proxy-consult' while action items
   + examples consistently use 'decision-proxy-evidence'.
   Aligned to '-evidence' (the canonical artifact name).

2. 'preserved verbatim' claim (line 99):
   Section heading said artifacts were 'preserved verbatim' but
   recent edits added proposal-flag annotations (PROPOSED notes
   on tools/memory/reconcile.py + tools/hygiene/check-memory-loop.sh).
   Renamed to 'preserved with proposal-flag annotations' which
   accurately describes the current state.

3. Drift-class subheading (line 320):
   Subheading said 'On the four drift classes' but the doc
   defines 5 (3 inside-loop + 2 outside-loop). Renamed to
   'On the five drift classes (3 inside-loop + 2 outside-loop)'.

4. P1-P2 sections claim (line 69):
   Text said extracted items target P1-P2 but the table has a
   P3 row (Provenance evidence bundles). Updated to 'P1, P2,
   and P3 sections (one P3 row covers the longest-horizon
   Provenance evidence bundles work)'.

5. Stabilize item count (line 395):
   'NOT' list said '4 S-effort items' but table lists 3
   Stabilize items (2 S + 1 M). Updated to '3 items: 2 S-effort
   + 1 M-effort'.

* drain(#430 Codex): note in-flight row + reflow orphaned 'are the' fragment

Two Codex post-merge findings on PR #430:

(line 72) — table contains in-flight row not covered by
'BACKLOG candidates' framing:
The intro said the table is BACKLOG candidates spanning
P1-P3, but Memory duplicate-title lint is tagged 'in-flight'
(landed elsewhere via PR #12). Updated intro to note the
in-flight row explicitly: 'BACKLOG candidates spanning P1,
P2, and P3 sections plus one in-flight row tracking work
that already landed elsewhere'.

(line 400) — orphaned line wrap:
'are the' was on its own line as a wrap artifact, making the
sentence harder to read. Reflowed so 'right next tick or two'
joins the prior line.
AceHack added a commit that referenced this pull request Apr 25, 2026
…ize L-effort item)

Amara's 4th ferry (PR #221 absorb) centerpiece proposal: replace
hand-maintained CURRENT-*.md distillations with generated views
over typed memory facts. Her sketch was ~40 lines of Python;
this is the design that downstream implementation follows.

~380 lines covering:

- MemoryFact record schema (id / subject / predicate / object /
  source_kind / source_path / source_anchor / timestamp_utc /
  supersedes / priority / status / confidence / tags)
- 6 schema invariants (at-most-one-active-per-canonical-key +
  monotone-timestamps-on-chain + retraction-leaves-trail + ...)
- Canonical-key normalization rules (7 apply; 3 deliberately
  NOT applied to preserve distinctions)
- Reconciliation pseudocode (group by canonical key, detect
  conflicts, follow supersession chains)
- Conflict output format → CONTRIBUTOR-CONFLICTS.md rows
- Rendering rules for CURRENT-<maintainer>.md + MEMORY.md
- 5-phase incremental migration (schema adoption → generator
  prototype → mechanical backfill → cutover → LLM extraction)
- CI integration hooks composing with rows #58, #59, #12
- Worked examples (MF-2026-04-23-001 "Aaron endorses
  deterministic reconciliation"; MF-2026-04-23-004 "Aaron
  grants full GitHub access")
- 5 open questions for Phase 1 PR design decisions

Composes with:

- Otto-73 retractability-by-design foundation — MemoryFact
  status (active / superseded / retracted) is the retraction-
  native primitive at the memory substrate
- PR #222 decision-proxy-evidence — consulted_memory_ids
  can now reference MemoryFact.id directly
- PR #225 memory-reference-existence CI (row #59) — generated
  output preserves the invariant by construction
- Zeta's ZSet algebra — MemoryFact records ARE Z-set entries
  at the memory layer; same primitive, different surface

Addresses MEMORY.md cap-drift (Otto-70 snapshot-tool
surfaced 58842 bytes vs. 24976-byte cap): a generated
index can be bounded by construction (top-N most-recent,
archive the rest).

Not implementation. Research doc only. Downstream arc:
schema adoption (S) → generator prototype off-CI (S-M) →
mechanical backfill (M) → cutover with retractability (M) →
LLM-assisted extraction (L research).

Amara Determinize-stage: 3/5 (with this PR).
  ✓ Live-state-before-policy (PR #224)
  ✓ Memory reference-existence lint (PR #225)
  ✓ Memory reconciliation algorithm design (this PR)
  Remaining:
  - Generated CURRENT-*.md views (L; this doc's Phase 2)
  - Memory duplicate-title lint enforcement (partial via
    AceHack PR #12; graduates via batch-sync)

Per Aaron Otto-73 retractability foundation: the design
itself embodies the thesis — supersession + status +
retraction make the memory layer's reconciliation
deterministic, same primitive as Zeta's data layer.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
AceHack added a commit that referenced this pull request Apr 25, 2026
…ize L-effort item)

Amara's 4th ferry (PR #221 absorb) centerpiece proposal: replace
hand-maintained CURRENT-*.md distillations with generated views
over typed memory facts. Her sketch was ~40 lines of Python;
this is the design that downstream implementation follows.

~380 lines covering:

- MemoryFact record schema (id / subject / predicate / object /
  source_kind / source_path / source_anchor / timestamp_utc /
  supersedes / priority / status / confidence / tags)
- 6 schema invariants (at-most-one-active-per-canonical-key +
  monotone-timestamps-on-chain + retraction-leaves-trail + ...)
- Canonical-key normalization rules (7 apply; 3 deliberately
  NOT applied to preserve distinctions)
- Reconciliation pseudocode (group by canonical key, detect
  conflicts, follow supersession chains)
- Conflict output format → CONTRIBUTOR-CONFLICTS.md rows
- Rendering rules for CURRENT-<maintainer>.md + MEMORY.md
- 5-phase incremental migration (schema adoption → generator
  prototype → mechanical backfill → cutover → LLM extraction)
- CI integration hooks composing with rows #58, #59, #12
- Worked examples (MF-2026-04-23-001 "Aaron endorses
  deterministic reconciliation"; MF-2026-04-23-004 "Aaron
  grants full GitHub access")
- 5 open questions for Phase 1 PR design decisions

Composes with:

- Otto-73 retractability-by-design foundation — MemoryFact
  status (active / superseded / retracted) is the retraction-
  native primitive at the memory substrate
- PR #222 decision-proxy-evidence — consulted_memory_ids
  can now reference MemoryFact.id directly
- PR #225 memory-reference-existence CI (row #59) — generated
  output preserves the invariant by construction
- Zeta's ZSet algebra — MemoryFact records ARE Z-set entries
  at the memory layer; same primitive, different surface

Addresses MEMORY.md cap-drift (Otto-70 snapshot-tool
surfaced 58842 bytes vs. 24976-byte cap): a generated
index can be bounded by construction (top-N most-recent,
archive the rest).

Not implementation. Research doc only. Downstream arc:
schema adoption (S) → generator prototype off-CI (S-M) →
mechanical backfill (M) → cutover with retractability (M) →
LLM-assisted extraction (L research).

Amara Determinize-stage: 3/5 (with this PR).
  ✓ Live-state-before-policy (PR #224)
  ✓ Memory reference-existence lint (PR #225)
  ✓ Memory reconciliation algorithm design (this PR)
  Remaining:
  - Generated CURRENT-*.md views (L; this doc's Phase 2)
  - Memory duplicate-title lint enforcement (partial via
    AceHack PR #12; graduates via batch-sync)

Per Aaron Otto-73 retractability foundation: the design
itself embodies the thesis — supersession + status +
retraction make the memory layer's reconciliation
deterministic, same primitive as Zeta's data layer.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
AceHack added a commit that referenced this pull request Apr 25, 2026
…e 3/5, L-effort design) (#226)

* research: memory reconciliation algorithm — v0 design (Amara Determinize L-effort item)

Amara's 4th ferry (PR #221 absorb) centerpiece proposal: replace
hand-maintained CURRENT-*.md distillations with generated views
over typed memory facts. Her sketch was ~40 lines of Python;
this is the design that downstream implementation follows.

~380 lines covering:

- MemoryFact record schema (id / subject / predicate / object /
  source_kind / source_path / source_anchor / timestamp_utc /
  supersedes / priority / status / confidence / tags)
- 6 schema invariants (at-most-one-active-per-canonical-key +
  monotone-timestamps-on-chain + retraction-leaves-trail + ...)
- Canonical-key normalization rules (7 apply; 3 deliberately
  NOT applied to preserve distinctions)
- Reconciliation pseudocode (group by canonical key, detect
  conflicts, follow supersession chains)
- Conflict output format → CONTRIBUTOR-CONFLICTS.md rows
- Rendering rules for CURRENT-<maintainer>.md + MEMORY.md
- 5-phase incremental migration (schema adoption → generator
  prototype → mechanical backfill → cutover → LLM extraction)
- CI integration hooks composing with rows #58, #59, #12
- Worked examples (MF-2026-04-23-001 "Aaron endorses
  deterministic reconciliation"; MF-2026-04-23-004 "Aaron
  grants full GitHub access")
- 5 open questions for Phase 1 PR design decisions

Composes with:

- Otto-73 retractability-by-design foundation — MemoryFact
  status (active / superseded / retracted) is the retraction-
  native primitive at the memory substrate
- PR #222 decision-proxy-evidence — consulted_memory_ids
  can now reference MemoryFact.id directly
- PR #225 memory-reference-existence CI (row #59) — generated
  output preserves the invariant by construction
- Zeta's ZSet algebra — MemoryFact records ARE Z-set entries
  at the memory layer; same primitive, different surface

Addresses MEMORY.md cap-drift (Otto-70 snapshot-tool
surfaced 58842 bytes vs. 24976-byte cap): a generated
index can be bounded by construction (top-N most-recent,
archive the rest).

Not implementation. Research doc only. Downstream arc:
schema adoption (S) → generator prototype off-CI (S-M) →
mechanical backfill (M) → cutover with retractability (M) →
LLM-assisted extraction (L research).

Amara Determinize-stage: 3/5 (with this PR).
  ✓ Live-state-before-policy (PR #224)
  ✓ Memory reference-existence lint (PR #225)
  ✓ Memory reconciliation algorithm design (this PR)
  Remaining:
  - Generated CURRENT-*.md views (L; this doc's Phase 2)
  - Memory duplicate-title lint enforcement (partial via
    AceHack PR #12; graduates via batch-sync)

Per Aaron Otto-73 retractability foundation: the design
itself embodies the thesis — supersession + status +
retraction make the memory layer's reconciliation
deterministic, same primitive as Zeta's data layer.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* drain(#226 P0+P1×2+P2×3 Codex): retraction semantics + cap consistency + smart-quote + pseudocode init + present-with-schema

Six substantive Codex findings on memory-reconciliation algorithm doc:

P0 (line 202) — retraction semantics inconsistency:
reconcile() filtered by status == 'active' which masked the
intent. Added explicit retraction-semantics docstring:
- Facts transition via explicit FactRetracted / FactSuperseded
  events; never deleted, only marked.
- reconcile() ignores retracted/superseded for liveness but
  STILL considers them when checking version-chain integrity.
- Updated chain check to operate over ALL facts in the group
  (including retracted/superseded), not just active ones —
  chain integrity needs the full history.

P1 (line 187) — stable fact identity vs grouping key:
Distinguished fact ID (stable identity, unique) from
(subject, predicate, canonical_key) grouping tuple (which
multiple facts can share under invariant-2's collision
case). Comment makes the distinction explicit.

P1 (line 270) — MEMORY.md cap inconsistency:
Default 30KB exceeded FACTORY-HYGIENE row #11 cap (24,976
bytes). Updated to 24,000 bytes — strictly under the hard
cap with ~1KB headroom for header/annotation overhead.

P2 (line 130) — smart-quote example ambiguous:
Both sides showed plain ASCII ('"' / "'"). Replaced with
explicit Unicode codepoint references (U+201C/D for
double, U+2018/9 for single) so the rule is unambiguous
in plain-ASCII source.

P2 (line 186) — pseudocode by_key[k] used before init:
Switched to defaultdict(list); added a comment noting the
equivalence to 'if k not in by_key: by_key[k] = []' for
non-Python implementers.

P2 (line 216) — CONTRIBUTOR-CONFLICTS.md 'empty' wording:
File is present and contains a schema; just unpopulated.
Updated text to 'present-with-schema-but-unpopulated; this
design starts populating it via the generator'.

* drain(#226 P1+P2 Codex): chain-head liveness + chain-integrity for retired groups

P1 (line 210) — chain-HEAD liveness, not 'any active in group':
The reconcile filter marked a key live whenever any record
in the group had status==active. That's wrong — a key with
active(t=1) → retracted(t=2) has an earlier active record
but the HEAD of the supersession chain is retracted, so the
key is not live. Fix: `follow_supersession_to_head(group)`
walks supersedes-pointers to find the most-recent record;
liveness keyed on its status == active.

P2 (line 224) — chain integrity for fully retired groups:
The chain-integrity check looped over `accepted.items()`,
which only included keys with at least one active record.
Retired groups (all members retracted/superseded) could
have broken chains and we'd silently miss them. Fix: loop
over `by_key.items()` (all groups, including fully retired
ones). Chain integrity is independent of liveness.

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant