Skip to content

chore(memory): promote strong-fit configuration drafts from memory-pipeline for review - #130

Merged
Hareet merged 8 commits into
mainfrom
memory/promote-configuration
Aug 5, 2026
Merged

chore(memory): promote strong-fit configuration drafts from memory-pipeline for review#130
Hareet merged 8 commits into
mainfrom
memory/promote-configuration

Conversation

@Hareet

@Hareet Hareet commented Jun 24, 2026

Copy link
Copy Markdown
Member

Promotes 10 strong-fit configuration drafts from agent-memory/_pending/ into agent-memory/domains/configuration/issues/ for squad content review.

Categories: feature (6), bug (4)
Themes: translations & RTL support, branding/partners doc validation, header-tab ordering, UI-extension service-worker rebuilds.

All 10 carry domainFit: strong + a ## Domain Rationale section. 18 weak-fit drafts deferred to Stream Cconfiguration was a catch-all in this run (64% weak), so this PR is intentionally the distilled minority.

@sugat009 sugat009 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes, though to be clear the fix is upstream and not something to patch by hand here. This seeder faithfully promotes what the distillation pipeline generated, so nothing is wrong with the promotion itself. The problem is in the drafts the pipeline produced, and I verified it against the live medic/cht-core API for every draft in this PR.

The defect: issueNumber / issueUrl name the merge PR, not the resolved issue

One precise note up front, because the intuitive version of this is not what is happening: issueNumber and issueUrl always agree with each other (the URL is literally /issues/<issueNumber>). The bug is that in 4 of 10 drafts here, that shared number is a pull request, so /issues/N silently redirects to /pull/N. The real resolved issue survives only in the PR-title slug. For example:

  • 10198-fix8026-validate-empty-branding-doc.md stores issueNumber: 10198 / issueUrl: .../issues/10198, but 10198 is the merge PR ("fix(#8026): validate empty branding doc"). The real issue is #8026 (closed): "Admin app fails to update branding if existing document is malformed".
  • 9407-fix9406-disable-unsupported-languages.md stores issueNumber: 9407 / issueUrl: .../issues/9407, but 9407 is the merge PR ("fix(#9406): disable unsupported languages"). The real issue is #9406 (closed): "Update default configurations to disable unsupported languages".

This is the same scraper behaviour flagged on #121, and it is pipeline-wide: across the four clean seeders, 60 of 107 drafts are affected.

Why request-changes rather than merge-and-fix-later

This corpus is the agent's memory of resolved issues (consumed by the Context Analysis Agent, see #135). A reference that resolves to a PR instead of the issue is simply wrong data, and it specifically defeats #135's planned de-duplication by issue id, since the "id" ends up being the PR id. Regenerating the drafts after the upstream fix will rewrite most of these files anyway, so merging now would churn the corpus twice.

Suggested fix (at the source, not file by file)

  1. Fix the distiller/scraper to take the resolved issue from the type(#N): PR title (the filename slug already extracts it correctly), and keep the PR number in source_pr where it belongs.
  2. Regenerate and re-promote this domain's drafts.
  3. Add de-duplication by real issue id (also a #135 acceptance item).

Open to discussing the approach. Once the drafts carry the real issue references, this should be a quick re-review.

Hareet and others added 3 commits July 16, 2026 18:12
…ly, configuration)

Deterministic relink via #129's relink-issues tool: drafts whose identity
keys recorded the merge PR now point at the resolved issue. Frontmatter
id/issueNumber/issueUrl lines only; bodies untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Per sugat009's review on #130: the 4 mislinked identity keys were fixed
by the relink commit; this follow-up verifies and polishes the corpus.
All 10 PR-to-issue mappings verified against the live cht-core API
(0 mismatches) — including 10555, whose issueNumber 10556 is a genuine
body closing ref ("Closes #10556", the pt-BR translations request),
not a distiller artifact.

Also: scrub reviewer/process narrative and classifier seed references
from 7 files (technical content kept, attribution removed), and add the
optional source_prs schema definition (identical to the other seeders).
No duplicate issueNumbers; validate-schema 74/74.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Hareet
Hareet force-pushed the memory/promote-configuration branch from 1720724 to f80479e Compare July 17, 2026 04:12
@Hareet

Hareet commented Jul 17, 2026

Copy link
Copy Markdown
Member Author

@sugat009 Same as the others.

Rebased onto main and addressed the review: identity keys relinked via #129's tool (4 files, same treatment as merged #129); all 10 PR→issue mappings re-verified against the cht-core API, zero mismatches. The deterministic relink supersedes the "regenerate and re-promote" suggestion — #129's merge established that approach. Also scrubbed process narrative from the prose and added the optional source_prs schema field used by the sibling seeders' duplicate collapses.

@Hareet
Hareet requested a review from sugat009 July 17, 2026 04:12

@sugat009 sugat009 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Content re-review. Identity/dedup/schema clean. Remaining (mostly distillation fidelity):

  • issue (accuracy): 10604, 8722, 11021 carry wrong/fabricated technical detail (inline).
  • nitpick (leakage): 9696 Domain Rationale ("…the seed", "explicit strong fit"); strip.
  • nitpick: 96969727 are an in-batch RTL/translations pair (issues #9682/#9683) but related_issues doesn't cross-link them; backfill.

Cross-cutting (whole promote batch, not blocking this PR alone): filenames still encode the PR number while frontmatter is issue-keyed, and two draft schemas coexist (machine-distilled vs hand-authored) — worth a cleanup pass. Full detail + re-runnable Verify commands are in my consolidated review notes.

Comment thread agent-memory/domains/configuration/issues/8722-feat8075-update-cht-branding.md Outdated
Hareet and others added 2 commits July 27, 2026 18:36
Every claim in these ten drafts was checked against the medic/cht-core commit it
was distilled from, using word-bounded `git grep`, `git diff-tree --name-status`
and `git ls-tree`. 124 claims verified true; the corrections below are the ones
the source contradicted. Reviewer-flagged items are marked [R].

10604 — the draft described the wrong bug and the wrong fix:
- [R] the view is `medic-client/doc_by_type`; `docs_by_type` exists nowhere
  (0 hits at 06d2e3abe and on master; the real view has 22).
- [R] no migration ever changed a view path. #10255 (de02d8421) removed the
  `translations` special case from the doc_by_type map, so the view stopped
  emitting `['translations', doc.enabled]` and its `{code,name}` value; that PR
  updated two admin controllers but missed the languages service.
- the fix did not repoint at a "current view path" — it replaced the query with
  an allDocs range scan over the `messages-` prefix and projects off `row.doc`;
  the lodash/core import was dropped.
- the spec was ADDED, not updated (diff-tree says A) — the service had no spec.
- dropped `related_workflows: [data-migration]`; no migration is involved.

8722 — [R] `add-branding-doc.js` was DELETED and replaced by
add-cht-branding-doc.js, not "added alongside, preserving the original"; the
replacement upserts and only overwrites attachments whose digest still matches
the old Medic assets. Removed the deleted file from entities, marked A/D in
Related Files, and dropped the anachronistic `ui-extensions` workflow tag (that
workstream first appears 2026-03-30; this anchor is 2023-11-28).

11021 — [R] `updateServiceWorker()` is defined and exported in config-watcher.js
itself (line 140/208), not imported from ui-extension.js, which exports only
getScript/getAllProperties. The documented test command was also broken:
`@medic/environment` exits(1) without COUCH_URL and db stubbing needs
UNIT_TEST_ENV=1, so the repo script `npm run unit-api` is the correct form.
The `ui-extension:` literal is deliberately left alone — that PR postdates the
local checkout and master has no PREFIXES.UI_EXTENSION, so either spelling could
be right.

9727 — `language.service.ts` does not read the rtl property off a doc; it holds
an in-memory registry. translation-loader.provider.ts reads `doc.rtl` and calls
setRtlLanguage. Dropped the anachronistic ui-extensions tag.

10278 — one line was added, in the attachment path only; the load path was
untouched. Also spelled out the two real guard forms (`res && res.resources` in
admin JS, `res?.resources ?? {}` in webapp TS).

10198 — the controller scaffolds one empty `resources` object and guards the
favicon/icon assignments; template safety comes from new ng-if attributes, not
from scaffolded keys.

9696/9727 — stripped classifier scaffolding from 9696's Domain Rationale and
cross-linked the RTL/translations pair in related_issues, both as requested in
review.

Verification: 124 claims confirmed against source, 0 contradicted. The
remaining unverifiable claims are confined to 11021 and 11057, whose source PR
numbers do not resolve to any commit in cht-core; nothing in either draft was
edited on the strength of a claim that could not be checked.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…in cht-core

This draft describes the config-watcher gaining a UI-extension doc-id branch that
calls updateServiceWorker(), and presents it as completed and tested. That code
is not in cht-core.

    git grep -n "startsWith" origin/master -- api/src/services/config-watcher.js
      :167  change.id.startsWith(PREFIXES.TRANSLATIONS)
      :171  change.id.startsWith('form:')

There is no UI-extension branch, and no commit anywhere in the repository
references the issue the draft claims to close. PREFIXES.UI_EXTENSION does now
exist in shared-libs/constants, so the work may be in flight, but nothing has
landed.

This is the same class as a draft distilled from an issue rather than a merged
PR: a memory asserting behaviour the codebase does not have is worse than no
memory, because an agent consuming the corpus cannot tell the difference. Better
re-distilled once the change merges.

Removing it also retires the one place on this branch where a correction had to
be guessed — the draft's 'ui-extension:' literal could not be checked, since
master carries no PREFIXES.UI_EXTENSION usage to compare against.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Hareet

Hareet commented Jul 28, 2026

Copy link
Copy Markdown
Member Author

Re-verified every factual claim in these drafts against the cht-core commit each was distilled from, rather than only the three items raised in review. Confirmed against source, with 13 corrections applied and one draft removed. After the removal the branch stands at 110 verified claims and no contradicted ones. These scripts from WIP were used.

Each correction below has the command that establishes it.


10604 — the draft described the wrong cause and the wrong fix

Beyond the view name, two larger problems:

There was no view-path migration. The stated root cause never happened — the view was never renamed or removed and is still present with ~20 consumers. What actually broke the page is #10255 removing the translations special case from the view's map function:

git -C $CORE log --format='%h %ci %s' 06d2e3abe2 -- ddocs/medic-db/medic-client/views/doc_by_type/
# de02d8421 2025-09-09 chore(#8157): remove use of translationdoc.enabled (#10255)

git -C $CORE show de02d8421 -- ddocs/medic-db/medic-client/views/doc_by_type/map.js
# removes: if (doc.type === 'translations') { emit(['translations', doc.enabled], {code,name}); return; }

That PR updated display-languages.js and display-translations.js but missed admin/src/js/services/languages.js, which kept querying key: ['translations', true] and got zero rows.

The fix is not a path correction. It abandons the view entirely:

git -C $CORE show 06d2e3abe2 -- admin/src/js/services/languages.js
# -  .query('medic-client/doc_by_type', { key: ['translations', true] })
# +  .allDocs({ start_key: 'messages-', end_key: 'messages-￰', include_docs: true })
# -  return _.map(result.rows, 'value');
# +  return result.rows.map(row => ({ code: row.doc.code, name: row.doc.name }));

And the spec was added, not updated — the service had no test before this PR:

git -C $CORE diff-tree --no-commit-id --name-status -r 06d2e3abe2
# M  admin/src/js/services/languages.js
# A  admin/tests/unit/services/languages.spec.js

The view name is corrected to doc_by_type throughout, and related_workflows: [data-migration] is dropped since no migration is involved.

8722 — the migration was deleted, not preserved

git -C $CORE diff-tree -M --no-commit-id --name-status -r d93b9162e2 -- api/src/migrations/
# D  api/src/migrations/add-branding-doc.js
# A  api/src/migrations/add-cht-branding-doc.js

Corrected, the deleted file removed from entities, and A/D status noted in Related Files. Also dropped a ui-extensions workflow tag from a 2023 draft — that workstream first appears 2026-03-30:

git -C $CORE log --all --reverse --format='%h %ci' -- api/src/services/ui-extension.js | head -1

9727 — rtl resolution misattributed

git -C $CORE grep -n -F -w setRtlLanguage 2175676e28
# providers/translation-loader.provider.ts:50   doc.rtl && this.languageService.setRtlLanguage(locale)
# services/language.service.ts:107              setRtlLanguage(code) { ... }

language.service.ts holds an in-memory registry and performs no document access; the provider reads doc.rtl. Anachronistic ui-extensions tag dropped here too (anchor is 2025-03-11).

10278 / 10198 — scope overstated

git -C $CORE show 9b26cbd0e2 -- admin/src/js/controllers/images-partners.js | grep '^+' | grep -v '^+++'
# exactly one added line, inside addAttachment; the load path is untouched

git -C $CORE show d9b2ef5750 -- admin/src/templates/images_branding.html | grep '^+' | grep -v '^+++'
# ng-if="favicon" / ng-if="icon"   ← where template safety actually comes from, not scaffolded keys

Review nitpicks

Classifier scaffolding stripped from 9696's Domain Rationale, and 9696 ↔ 9727 cross-linked in related_issues as the RTL/translations pair.


What was confirmed correct

110 claims verified positively across the nine remaining drafts, not merely "no error found" — Related-File membership with A/M/D status on every draft, and every named symbol located in the file the draft attributes it to. The strongest were 9727 (23), 8722 (20), 10604 (15 after correction), 10278 (14), 10198 (13). Nine claims remain unverifiable, all in 11057.

Drafts whose provenance I could not verify

Two drafts had no resolvable anchor, and this is not clone staleness: their PR numbers are stamped nowhere in history, even on a same-day clone. One is removed; the other is flagged.

11021 — removed from this PR: the described feature is not in cht-core.

git -C $CORE grep -n "startsWith" origin/master -- api/src/services/config-watcher.js
#   :167  change.id.startsWith(PREFIXES.TRANSLATIONS)
#   :171  change.id.startsWith('form:')      ← no UI-extension branch
git -C $CORE log --all --oneline --fixed-strings --grep="#11018"    # empty

PREFIXES.UI_EXTENSION exists in shared-libs/constants, but config-watcher.js has no UI-extension dispatch and nothing references the issue. That is the same situation you flagged on the smsparser draft — proposed work described as completed and tested — so I have dropped the draft rather than ship a memory asserting behaviour the codebase does not have. Worth re-distilling once the change merges.

Removing it also retired the one correction on this branch that would have had to be guessed: the draft's 'ui-extension:' literal could not be checked either way, since master carries no PREFIXES.UI_EXTENSION usage to compare against.

11057 — mechanism real, attribution wrong.

git -C $CORE grep -n -F -w weight origin/master -- webapp/src/ts/services/header-tabs.service.ts   # :23 :32 :41
git -C $CORE log --oneline -1 origin/master -- webapp/src/ts/services/header-tabs.service.ts
# 180c29ecf feat(#10224): support ui-extensions (#11050)

The weight ordering is real, but it arrived in #11050, not #11057. Worth confirming the source_pr before this one is trusted for provenance.

Nothing in 11057 was edited on the strength of an unverifiable claim — its substance checks out, only its source_pr is in doubt.

@Hareet
Hareet requested a review from sugat009 July 28, 2026 05:29
…ding fixes (configuration)

- 10604: the doc_by_type consumer count is scoped to the fix's era (18 files);
  #10822 (57ea9228b, 2026-07-01) has since moved consumers off the view and
  narrowed its index to form/user-settings — present-tense master claim was stale
- 11057: provenance is real, not doubtful — PR #11057 merged into the
  10224-ui-extensions feature branch; its merge commit IS source_sha (46c8f7c8e),
  unreachable from master only because the epic squashed via #11050 (180c29ecf).
  Added source_prs [#11057, #11050] and a Related Issues note so anchors resolve
  from a master clone
- 10278: 'browserify-compatibility const was documented' -> the reviewer-suggested
  ?. one-liner broke the admin browserify build (review thread), explaining the
  divergent admin/webapp guard spellings
- 10555: AI disclosure is a PR-description section, not a file comment; strip
  triage vocabulary ('catch-all') from the Domain Rationale
- 8722: complete (added)/(deleted) annotations on the logo asset Related Files

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Hareet

Hareet commented Jul 28, 2026

Copy link
Copy Markdown
Member Author

Before the re-review starts: I audited my own verification comment above and found two wrong conclusions in it, plus one stale claim it let through. Corrections landed in 3cd4124; validate-schema still passes (73/0), and the clone-scoping blind spot itself is now fixed in the verification tooling on #145 (adfb256). Same format as before — each point carries the command that establishes it.

The "unresolvable anchors" were real all along — my clone-scoped tooling was the problem

I wrote that 11057 and 11021 "had no resolvable anchor" and doubted source_pr: #11057. That was wrong. Both PRs are real and merged — into the 10224-ui-extensions feature branch, which reached master as the #11050 squash. The child PRs' merge commits exist only on the (deleted) feature branch, which is why git log --grep on a clone finds nothing:

curl -s https://api.github.com/repos/medic/cht-core/pulls/11057 | jq '{state, merged, base: .base.ref, merge_commit_sha}'
# "closed", true, "10224-ui-extensions", "46c8f7c8e43a969d9ecd12c65d3816b19664fd63"  ← exactly the draft's source_sha

git -C $CORE log -1 --format='%h %ci %s' 180c29ecf
# 180c29ecf 2026-06-22 feat(#10224): support ui-extensions (#11050)   ← how it reached master

The nine claims I logged as "unverifiable, all in 11057" are now verified, all true, against both the PR diff and current master:

git -C $CORE grep -n -w weight origin/master -- webapp/src/ts/services/header-tabs.service.ts
# :23–:57 defaults · :133 header_tabs app-settings override · :150 UI-extension weight · :162,:185 sorts

git -C $CORE grep -n SidebarTab origin/master -- webapp/src/ts/components/sidebar-menu/sidebar-menu.component.ts
# :23,:50 — the sidebar refactor (hardcoded TAB_MENU_OPTIONS → pre-ordered SidebarTab list) survived the squash

Blockers #10672/#10901 and the forum request are verbatim in issue #10908's body; cht-docs#2213 and the "most unit tests by Claude" disclosure are verbatim in PR #11057's. Draft change in 3cd4124: source_prs: [#11057, #11050] (the schema field's multi-PR-epic case) plus a Related Issues note carrying the master-reachable squash commit, so the anchor now resolves from a plain clone.

11021 stays dropped, but for a corrected reason. It was not the smsparser case — the work was real, merged into the epic, and tested. It was superseded during the epic's evolution: the #11050 squash lands no UI-extension dispatch in config-watcher.js and even removes the older extension-libs service-worker hooks. Master has no rebuild-SW-on-ui-extension-change behavior, so the memory stays out; nothing to re-distill unless that behavior returns.

curl -s https://api.github.com/repos/medic/cht-core/pulls/11021 | jq '{state, merged, base: .base.ref}'
# "closed", true, "10224-ui-extensions"

git -C $CORE show 180c29ecf -- api/src/services/config-watcher.js
# removals only: extensionLibs require, isLibChange dispatch, handleLibsChanges

One claim my pass verified against the wrong era — now time-scoped

10604 said the view "still exists on master with roughly fifteen consumers" (my comment above said ~20). Both figures were measured at the source commit and are stale on today's master: #10822 (2026-07-01) narrowed doc_by_type to indexing only form/user-settings and moved every remaining consumer off it.

git -C $CORE grep -l doc_by_type 06d2e3abe2 | wc -l     # 18 — at the fix
git -C $CORE grep -l doc_by_type origin/master | wc -l  # 0  — today
git -C $CORE log -1 --format='%h %ci %s' 57ea9228b
# 57ea9228b 2026-07-01 feat(#10638): not indexing common documents in doc_by_type (#10822)

The draft sentence is now era-scoped: 18 referencing files at the time of the fix, with the #10822 note for current master.

Three wording fixes in the same commit

  • 10278 — "a browserify-compatibility const was documented": what the review thread actually shows is that the suggested res?.resources one-liner broke the admin browserify build, which is why the Admin service keeps the ES5 guard while the Angular-CLI-built webapp uses res?.resources ?? {} (thread). Reworded accordingly.
  • 10555 — the AI disclosure is a section of the PR description, not a comment in the properties file (the file has zero comment lines). Also stripped the "not a catch-all pick" triage vocabulary from the Domain Rationale — same leakage class you flagged on 9696.
  • 8722 — completed the (added)/(deleted) annotations on the logo assets in Related Files.

Updated tally, from a fresh ground-claims run with the epic-aware resolver (#145's adfb256) against the same cht-core checkout as before (1f3e56f226): 9 drafts, 122 grounded / 0 ungrounded / 0 unverifiable / 0 anchor-unusable (was 110 / 0 / 9). The nine previously-unverifiable claims now ground with 11057 anchored at the epic squash — the report records the anchor as 180c29ecf with the note "resolved via GitHub API: medic/cht-core#11057 merged into 10224-ui-extensions; anchored at the squash of #11050". One previously-"verified" claim was contradicted by current master and is corrected above; everything else stands as posted.

Hareet added a commit that referenced this pull request Jul 28, 2026
FOURTH false-positive class, proven live on the promote-configuration
review (#130): a PR merged into a FEATURE branch that later squash-merged
onto master leaves no trace a clone can see. The child's merge commit
lives only on the deleted branch and no squash subject carries its
number, so both local strategies failed and nine TRUE claims in the
11057 draft degraded to unverifiable — and the same blind spot produced
a wrong "not in cht-core" provenance diagnosis on 11021's removal.

resolveAnchor now takes the repo slug and, when the clone alone cannot
name the commit, asks the GitHub API which LOCAL commit carries the PR:

- merged PR whose merge commit is in the clone but whose subject has no
  "(#N)" stamp (the SSO cluster) -> anchored directly;
- merged into a feature branch -> one hop: the PR whose HEAD is that
  branch (pulls?head=owner:branch) supplies the squash the clone can
  see (11057 -> 10224-ui-extensions -> #11050 / 180c29ecf).

Resolution only — adjudication never leaves git, a sha the clone lacks
is never anchored to, and every failure (gh missing, curl down, rate
limit, unmerged PR) degrades to the existing unverifiable semantics
rather than a defect or a crash. gh is tried first for the
authenticated rate limit; anonymous curl is the fallback. Anchors
resolved this way carry a note surfaced in claims.json and REPORT.md;
--no-api-resolve keeps a run fully offline.

Grounding against an epic squash reuses the sibling-union
over-approximation already accepted for source_prs: file-touched sees
the union of every child's changes and statuses reflect the landed
state.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@sugat009 sugat009 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Round 3 on the reworked head. All five findings from my last round are verified fixed: the 10604 rewrite is now the model for how these drafts should read (correct view name, accurate description of the allDocs replacement, time-scoped staleness), 8722 states the add-branding-doc.js deletion correctly, the 9696/9727 cross-links landed, the scaffolding is gone, and deleting 11021 rather than correcting it was the right call, since the hook it documented never reached master.

Requesting changes on the two residual items plus two nitpicks inline. Both residuals are the same secondary-section staleness pattern flagged in more volume on #120.

Hareet and others added 2 commits July 30, 2026 09:59
…nd it (configuration)

Sugat's two residuals and two nitpicks, plus the same class found
systematically rather than only where he pointed.

10198 — the draft contradicted itself in four places on the one
mechanism the grounding pass corrected. Solution says template safety
comes from the new ng-if attributes 'not from scaffolded keys', while
summary, Code Patterns and Design Choices all still credited the
scaffolding. Only Testing was flagged in review; a coherence pass over
the whole file found the rest. All four now agree: reads are guarded so
missing images stay undefined, the template hides them with ng-if, and
the single scaffolded 'resources' object exists because the submit path
writes into it. Also drops the stale 'One related case is not covered'
artifact — the merged spec covers both the empty-doc and null-resources
cases.

10278 — resource-icons.service.ts and resource-icon.service.spec.ts were
replaced by custom-resource.service.* in #11050 (180c29ecf), so both were
named in the present tense for paths that no longer exist. Time-scoped in
10604's style, with a paths note covering every mention rather than the
four lines review listed.

11057 — source_prs dropped. #11050 resolves #10224, not this draft's
#10908, so it never satisfied the field's 'All PR refs that resolve to
this issue'. Nothing is lost: the API resolver anchors this draft by
hopping from #11057's base branch, and the epic provenance was already
prose in Related Issues.

lastUpdated bumped on 10198, 9696, 9727 (review) and 9407 (found by the
new stale-timestamp check, which compares the stamp to the file's last
commit rather than eyeballing which drafts moved).

Gate: validate-schema 73 passed / 0 failed; verify-drafts --online 0
blocking / 0 warnings; check-coherence 0 contradictions.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…dit (configuration)

- 9407: the stamp was set to the date of its last CONTENT commit
  (2026-07-16), but setting it is itself an edit, so the branch's own
  stale-timestamp check then failed the file. The rule that actually holds
  is 'touch the file, stamp it today'.
- 10278: my (replaced by custom-resource.service.ts in #11050) suffix on
  an entities entry made a machine-readable path non-bare, which any
  downstream consumer matching on paths would miss. Reverted to the bare
  path; the caveat already lives in the Code Patterns note and the
  Related Files annotation, where prose belongs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Hareet added a commit that referenced this pull request Jul 31, 2026
…eading, not probing

Round 3 on #120/#130 was almost entirely defects no existing layer could
see. Each class below is now checked mechanically, with the LLM confined
to identifying candidates that code then verifies.

SELF-CONTRADICTION (new Layer 3, check-coherence.ts). A grounding pass
corrects the sections that assert mechanism against code and leaves the
interpretive ones asserting what it just disproved, so both halves ground
independently while the document tells two stories. 10198 says template
safety comes from ng-if attributes 'not from scaffolded keys' in Solution
and that the controller 'scaffolds the minimum keys the template
requires' in Design Choices. The model may only IDENTIFY pairs and must
quote both sides verbatim; verifyContradictions drops any pair whose
quotes do not occur in the file, so a hallucinated finding cannot land.

DRIFT (claim-probes.ts). resource-icons.service.ts was real when its PR
shipped and is gone today: checking only the anchor certifies it, checking
only master refutes it, and both are wrong — the claim is true, the tense
is not. A claim that grounds at its anchor is now re-checked against
master and flagged when the draft names a dead entity with no temporal
qualifier. Exits 3, not 1: nothing is disproven, so 'ungrounded' keeps
meaning 'this is wrong'.

CROSS-REFERENCE ACCURACY (verify-drafts.ts, --online). #10754 sat in
Related Issues glossed as 'Scheduled task duplicate processing'; it is
'Cookies not being sent with secure: true'. Every #N there is now
classified and its gloss compared to the real title, with only total
disjointness reported so paraphrase stays free. PRs cited as issues warn
unless labelled 'PR #N'.

SNIPPET FIDELITY (claim-probes.ts). The 4278 fence was a composite of two
real helpers, so every symbol in it probed clean while the block existed
nowhere. Fences are matched against every file the draft names,
whitespace- and comment-insensitively, with elision markers as segment
boundaries.

STALE TIMESTAMPS (verify-drafts.ts). lastUpdated must not predate the
file's last commit; 13 rewritten drafts kept their old stamp.

Also: the extraction prompt no longer turns a REMOVAL claim ('removed the
parseResponseBody helper') into an existence probe, which cost a false
flag last run; gh-classify gains describeNumber for titles; Draft carries
its absolute path so git pathspecs work when scanning a sibling worktree.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Hareet

Hareet commented Jul 31, 2026

Copy link
Copy Markdown
Member Author

All four items are fixed, and chasing the cause behind them turned up one more instance of the same class in a draft you had not flagged — that one is the reason this reply is longer than four lines. Head is b8004ca.

Your items

10198 Testing — your suggestion, verbatim. The merged spec does cover both cases (should not fail when branding doc is empty at :41, should not fail when resources is null at :53 in d9b2ef575), so "one related case is not covered" was a mid-review leftover with no referent.

10278 present-tense dead path — time-scoped in 10604's style, and the drift check found the problem was wider than the four lines you cited: webapp/tests/karma/ts/services/resource-icon.service.spec.ts is also gone, replaced by custom-resource.service.spec.ts in the same #11050 commit. Both now carry the qualification, with one note in Code Patterns explaining that the Admin service survived while the webapp side was replaced.

git -C $CORE cat-file -e origin/master:webapp/src/ts/services/resource-icons.service.ts || echo absent
git -C $CORE log --oneline --diff-filter=D -1 -- webapp/src/ts/services/resource-icons.service.ts
# 180c29ecf feat(#10224): support ui-extensions (#11050)

11057 source_prs — you are right that #11050 does not resolve #10908, so under that field's description it does not belong there. I removed source_prs from the draft entirely rather than trimming it to a single entry, since with source_pr: medic/cht-core#11057 present the array carried nothing. The epic provenance stays in the Related Issues prose where it reads as context rather than as a resolution claim. Worth noting it costs nothing mechanically: the anchor resolver reaches the same commit through #11057's base branch, so grounding still anchors this draft at 180c29ecf without the metadata.

lastUpdated — 10198, 9696 and 9727 bumped. A stale-timestamp check now enforces this (lastUpdated must not predate the file's last commit), which promptly caught a fourth I had missed, 9407, and then caught my first attempt at fixing it: I had set it to the date of the last content change, but setting the stamp is itself an edit, so the rule that actually holds is "touch the file, stamp it today".

The item you did not flag

Following your diagnosis as a class rather than a checklist, I built a check for it — an LLM identifies contradicting pairs and must quote both sides verbatim, then the script verifies mechanically that both quotes occur in the file and discards any that do not. Run blind across all nine configuration drafts it found exactly one thing, in 10198, which the round-2 grounding pass had half-corrected:

  • Solution (L53): "Template safety comes from new ng-if="favicon" / ng-if="icon" attributes on the two <img> tags, not from scaffolded keys."
  • Design Choices (L61): "the controller defensively scaffolds the minimum keys the template requires"

The summary and Code Patterns carried the same stale mechanism. Verified against d9b2ef575: the controller scaffolds only resources, guards the favicon/icon assignments behind if (doc._attachments && doc.resources) so they stay undefined, and the template is protected by the two new ng-if attributes. All four sections now say that. This is the same shape you found in volume on #120 — it was here too, one draft deep.

Gate

validate-schema 73/0. verify-drafts --online (identity, duplicates, near-miss symbols, leakage, cross-references, timestamps): 0 blocking, 0 warnings across all nine. ground-claims: 117 grounded, 0 ungrounded, 0 unverifiable, 0 anchor-unusable, 0 stale-as-written, 0 unmatched code fences, all nine drafts anchored — 11057 via its epic squash 180c29ecf, as described above, the other eight at their own commits. Coherence: 0 contradictions.

Two things I would rather say than have you find:

  • The coherence check samples rather than exhausts. Three passes over the messaging batch returned pairs with different membership each time, so a single clean pass is weak evidence. Configuration has been clean across multiple passes and an independent audit, which is why I am reporting it as clean rather than proven.
  • The cross-reference audit initially flagged your #10901 "Blocker for #10908" gloss as a mismatch. That was my check being wrong, not the draft: a gloss describing a relationship is not a paraphrase of a title, and relationship glosses are now exempt from that comparison.

@Hareet
Hareet requested a review from sugat009 July 31, 2026 23:59
Hareet added a commit that referenced this pull request Aug 3, 2026
…argets)

Same class the reviewer identified on #120 and #130: the grounding pass
corrected the sections that assert mechanism against code and left summary
and Design Choices asserting what it had just disproved. Every pair below
was found by check-coherence over two passes and then verified against
cht-core; in each case the corrected body was right and the stale side was
rewritten to match it.

- 10362: summary said the service is 'wired into task state' and Design
  Choices said it consumes task state, while Code Patterns says it reads no
  NgRx state - it subscribes to contactsMarkedAsDirty and fetches docs.
- 10480: summary said the counter mirrors the unread-count pattern; Code
  Patterns says the PR generalises that flow (setUnreadCount became
  setBubbleCounter). Testing credited the rules-engine integration test
  with 'the count computation'; the engine contributes the showTask
  predicate (index.js:117) and the count is computed in the webapp.
- 9232: summary said the filter appears only for multi-facility users and
  single-facility users see no change; Solution says there is no
  facility-count term, so everyone with a facility list gets it.
- 9553: summary said the fix reconciles state against the configuration;
  the body says isStale only checks the blob has targets and aggregate keys
  and never reads the configured targets. Solution also said turnover
  re-scopes/resets emissions; Code Patterns says they are preserved.
- 9705: Design Choices claimed the fix throws on WRITE errors; the change is
  to a read catch-all, and the file's one bulkDocs still only console.errors.
- 10623: Design Choices said the filters were reused rather than built;
  overdue-filter and task-type-filter are new components, both on master.
- 8932: summary called the flashed text 'empty-state messages'; Root Cause
  shows they are end-of-list messages gated on has-items being true.
- 10371: Design Choices claimed a new reusable telemetry test util;
  tests/utils/telemetry.js pre-existed and was modified.
- 10324: summary said targets analytics had no way to review prior periods;
  Problem says target-aggregates already had that filter since #9317.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@sugat009 sugat009 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving. All four round-3 comments verified fixed at b8004ca:

  • 10198's stale "One related case is not covered by the fix" is gone, replaced with accurate coverage of both the empty-doc and null-resources cases.
  • 10278 is now properly time-scoped, with a "Note on paths" paragraph naming custom-resource.service.ts, PR #11050 and commit 180c29ecf, and both Related Files entries annotated. This is the 10604 pattern applied correctly, and it is the model I would point the other domain branches at.
  • 11057's stray source_prs entry for #11050 is removed.
  • The three stale lastUpdated values are bumped to 2026-07-30.

Zero residual findings. CI green at b8004ca.

@Hareet
Hareet merged commit ff2223a into main Aug 5, 2026
4 checks passed
@Hareet
Hareet deleted the memory/promote-configuration branch August 5, 2026 03:39
Hareet added a commit that referenced this pull request Aug 11, 2026
…y-pipeline for review (#123)

* chore(memory): promote strong-fit tasks-and-targets drafts for review

* fix(#135): relink id/issueNumber/issueUrl to real issues (metadata-only, tasks-and-targets)

Deterministic relink via #129's relink-issues tool: drafts whose identity
keys recorded the merge PR now point at the resolved issue. Frontmatter
id/issueNumber/issueUrl lines only; bodies untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(#135): collapse duplicate clusters + review fixes (tasks-and-targets)

Per sugat009's review on #123: fix the hallucinated identity on 9232 —
its stored key was medic/care-teams#137 mis-stamped as cht-core; the
memory is now keyed cht-core-9231 (PR title scope) with the care-teams
Related Issues lines dropped. Collapse the 3 clusters to one memory per
issue with source_prs[]: 9231 (9232+9282+9317 sequential facets), 9431
(9486 + 4.13.x sibling 9549), and 9552 (9553+9555+9569+9570 — the two
distinct sub-fixes attributed separately, backport lines noted).

Drop 8838 (closes no tracked issue — skip-and-flag policy). Cross-domain
dedup: 9099 (#6543 facet) moves to the authentication canonical; 10432
(#10344) to the contacts corpus's existing memory; 9975 (#9974) to the
forms corpus's existing memory — refs recorded there in touch-ups.

Forced fits re-annotated weak (10390 datasource, 8932 cross-component,
10786 telemetry pipeline). Process narrative scrubbed from 11 files
(named reviewers, CI-status and AI-change chronology).

All 35 mappings verified (live cht-core API + the reviewer's own
closingIssuesReferences audit for rate-limited cluster members);
validate-schema 89/89; no duplicate issueNumbers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(#136): ground tasks-and-targets drafts against cht-core source

Every factual claim in the twenty-five drafts on this branch was checked against
the cht-core commit it was distilled from. 319 claims confirmed; 71 corrections
applied. Each correction was re-checked by a second pass instructed to refute it.

Two drafts on this branch contradicted each other, and the source settled both:

BACKPORT LINE. 9553 said the fix "was backported to the 4.1.x line (PR #9555)"
while its sibling 9486 said 4.13.x. The backport commit c8a7f13ad is titled
"...for 4.13.x (#9555)" and is an ancestor of origin/4.13.x but not of
origin/4.1.x. 9553 corrected; 9486 was already right.

TASK ORDERING. 10362 said tasks are "ordered by due date and then priority";
9980 said priority descending with due date as tie-break. The shared comparator
in shared-libs/task-utils runs a priority cascade first and only reaches
compareDates() when priorities are invalid or equal, so 9980 is right and 10362
was inverted. Corrected in 10362.

10362 was wrong in three further ways: the notifications are Android device
notifications delivered through globalThis.medicmobile_android, not in-app ones,
and are inert in a browser; the new service reads no NgRx state, only
RulesEngineService.contactsMarkedAsDirty; and the ordering comparator was not new
logic but an extraction of an existing private function out of the tasks reducer.

Also corrected: 10772 described its e2e spec as added when the commit modified it
(only the target config was added), plus prior-state overstatements, A/M status
confusions and telemetry key inexactness across the branch.

Left unedited deliberately: 10390's cht-datasource module names, which conflict
with 10423's but cannot be checked because its own commit is unrecoverable; and
10436's Mocha-harness attribution, for the same reason. Six proposed corrections
did not survive re-checking. 108 claims remain unverifiable, chiefly on drafts
whose PR numbers appear nowhere in cht-core history. Nothing was edited on the
strength of a claim that could not be checked.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(#136): bump lastUpdated on all 25 drafts (tasks-and-targets)

Every draft in the batch was edited by the relink, dedup and grounding
commits without its stamp moving, so all 25 failed the stale-timestamp
check. Stamped today rather than with each file's last content-change
date: the stamp edit is itself a commit, so a content date fails on the
very commit that sets it - the rule learned twice on the configuration
and messaging branches.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(#136): time-scope four drafts whose epic renamed their files (tasks-and-targets)

10324, 10371, 10436 and 10507 all merged into the 10140_previous-month-targets
feature branch and reached master only in that epic's squash, #10423
(622c625427). The epic reshaped them on the way:

- the e2e directory was renamed analytics/ -> targets/, so the
  tests/e2e/default/analytics/analytics.wdio-spec.js these drafts name is
  tests/e2e/default/targets/analytics.wdio-spec.js on master;
- webapp/src/ts/libs/config.ts, created by 10507 and renamed by 10436, does
  not exist on master at all - only .mocharc.js survives of the mocha
  harness, and the subtitle handling now lives in rules-engine.service.ts;
- RulesEngineService.fetchTargets() is spelled as a bare fetchTargets() on
  the service (rules-engine.service.ts:501) and really did gain the
  reporting-period argument this draft describes.

Every path is accurate for its own PR, which is why grounding at the anchor
passed them; they are wrong only as directions for a reader looking at
master today. Each now says so, with the landed location where there is
one. This is the drift class the probe was built for, arriving in bulk
because five drafts share one epic.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(#136): twelve self-contradictions across nine drafts (tasks-and-targets)

Same class the reviewer identified on #120 and #130: the grounding pass
corrected the sections that assert mechanism against code and left summary
and Design Choices asserting what it had just disproved. Every pair below
was found by check-coherence over two passes and then verified against
cht-core; in each case the corrected body was right and the stale side was
rewritten to match it.

- 10362: summary said the service is 'wired into task state' and Design
  Choices said it consumes task state, while Code Patterns says it reads no
  NgRx state - it subscribes to contactsMarkedAsDirty and fetches docs.
- 10480: summary said the counter mirrors the unread-count pattern; Code
  Patterns says the PR generalises that flow (setUnreadCount became
  setBubbleCounter). Testing credited the rules-engine integration test
  with 'the count computation'; the engine contributes the showTask
  predicate (index.js:117) and the count is computed in the webapp.
- 9232: summary said the filter appears only for multi-facility users and
  single-facility users see no change; Solution says there is no
  facility-count term, so everyone with a facility list gets it.
- 9553: summary said the fix reconciles state against the configuration;
  the body says isStale only checks the blob has targets and aggregate keys
  and never reads the configured targets. Solution also said turnover
  re-scopes/resets emissions; Code Patterns says they are preserved.
- 9705: Design Choices claimed the fix throws on WRITE errors; the change is
  to a read catch-all, and the file's one bulkDocs still only console.errors.
- 10623: Design Choices said the filters were reused rather than built;
  overdue-filter and task-type-filter are new components, both on master.
- 8932: summary called the flashed text 'empty-state messages'; Root Cause
  shows they are end-of-list messages gated on has-items being true.
- 10371: Design Choices claimed a new reusable telemetry test util;
  tests/utils/telemetry.js pre-existed and was modified.
- 10324: summary said targets analytics had no way to review prior periods;
  Problem says target-aggregates already had that filter since #9317.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(#136): drift and two wrong file statuses (tasks-and-targets)

Real defects:
- 9553 called target-accuracy.wdio-spec.js an added e2e spec; it was
  modified. Its migrateStaleState sentence is also attributed to #9553,
  but the symbol enters in the #9569/#9570 follow-up - it is absent at
  dc47c51e4 and present on master at target-state.js:124.
- 9980 called tasks.spec.ts added; diff-tree says modified.

Drift - true at the anchor, gone from master, now time-scoped:
- 10362's shared-libs/task-utils/test/order-by-due-date-and-priority.js,
  removed by #10701.
- 9232's analytics-target-aggregates-sidebar-filter component and spec,
  folded into the shared analytics sidebar filter by the same #10140 epic
  that reshaped four other drafts in this batch; its modules.module.ts,
  dissolved by the Angular 19 standalone migration (#9759); and the
  can_view_old_filter_and_search / can_view_old_action_bar permissions,
  both retired from master.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(#136): keep 9232 entities a bare path (tasks-and-targets)

My drift annotation landed on the entities entry rather than the Related
Files line - replace(...,1) hits the frontmatter occurrence first - and the
colon inside it made YAML parse the item as a map, so validate-schema went
88/1. Reverted to the bare path, annotation moved to Related Files where
prose belongs. Same mistake as 10278 on the configuration branch; entities
is machine-readable and any downstream consumer matching on paths would
miss an annotated one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(#136): the two contradictions that survived three passes (tasks-and-targets)

Both had resisted an earlier fix because I corrected one statement and left
a third one standing - the same one-section-at-a-time failure this whole
exercise is about.

9232 made three incompatible claims about what gates the filter UI. The
summary said multi-facility users only; I corrected it to 'has a facility
list at all', which was also wrong; Code Patterns still said 'only when
facility_id resolves to multiple facilities'. What Solution actually
documents is canDisplayFilterButton() gating on !isAdmin plus the legacy
permissions being absent, with facility count controlling only the radio
group inside the sidebar. All four statements now say that.

9553 said the interval-turnover migration fires 'when the persisted
reporting interval no longer matches the current CalendarInterval' while
Code Patterns says it reuses the shape check rather than comparing
intervals. My previous edit fixed the emissions half of that sentence and
left the trigger clause. Rewritten: load() runs the shape check on every
hydration.

Also time-scoped the two legacy permission constants where they are quoted,
both retired from master.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(#136): cross-reference glosses and PR labels (tasks-and-targets)

From the online audit, which this branch had never had - an earlier attempt
rate-limited 23 of 25 drafts, and record caching (baeb04b) is what made a
complete 25-draft scan fit the 60/hour anonymous budget. It finished with
0 unverified.

Blocking:
- 9486 cited #9432 as 'recalculate tasks/targets automatically on document
  or state changes (debounced)'. #9432 is 'Merge ensureTaskFreshness and
  ensureTargetFreshness into single event' - a performance issue about
  folding two 120-second background refreshes into one, not about
  triggering on document changes.
- 9718 cited #9486 as an issue describing 'prior work improving
  recalculation'. #9486 is a PR, 'feat(#9431): always aggregate and store
  targets'. Now labelled and titled.

Also: #6209's gloss was fair but vague enough to trip the weak-overlap
warning, so it now carries the real title; and 9232's #9267/#9283/#9305 are
PRs cited as issues, now labelled PR #N.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(#136): five more partial-fix mismatches (tasks-and-targets)

Three of these five exist because an earlier commit in this same PR
corrected one section and left a sibling asserting the old thing - the
failure mode this whole exercise is about, committed by the person fixing
it, twice now. Recording that plainly:

- 9232: my summary rewrite said the facility radio group is the only
  element gated on facility count; Design Choices, Solution, Code Patterns
  and Testing all also list the per-aggregate facility indicator.
- 9705: I corrected Design Choices to the read-side catch-all and left the
  summary saying errors were swallowed 'while saving' with 'failed writes'.
- 9553: I corrected Testing to 'modified not created' for the e2e
  target-accuracy spec and left Solution saying the spec was added.

Two were pre-existing:
- 10436's summary attributed the wrong-subtitle defect to both analytics
  pages; Problem confines it to target-aggregates.
- 9980's Design Choices claimed changes were 'confined to the webapp' while
  Solution lists config/default/tasks.js, which is not in the webapp.

Coherence over three passes went 5/2/2 before these fixes to 2/3/0 after
the previous round, with 9232 and 9553 dropping from every pass to one -
the sampling behaviour is why the gate is three passes and not one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(#136): two drafts called modified specs 'added' (tasks-and-targets)

Both are real imprecision the exhaustive pass caught, not tool artifacts:

- 10390 lists five mocha specs as added for the new datasource module.
  Three were; test/qualifier.spec.ts and test/index.spec.ts already existed
  and PR #10390 extended them.
- 10786 says it 'added sentinel replications.spec.js and mocha
  purger.spec.js coverage'. The coverage was added, but both spec files
  pre-existed and were modified. Reworded to 'extended the existing'.

Small, but the whole point of the corpus is that a reader can trust a file
list, and 'added' versus 'extended' is exactly the sort of detail an agent
would act on.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(#136): three contradictions the x3 coherence gate surfaced (tasks-and-targets)

9705 recurred in all three passes, which is the signal that separates a real
finding from sampling noise - and it was mine. My earlier summary said the
catch-all 'swallowed every error into a synthesised default document'. The
code at the anchor's parent is 'if (err.status === 404)': only a 404 produced
a fresh doc, every other rejection fell through returning nothing. So the
failure mode was worse than the summary claimed - neither a document nor an
error - and the Root Cause section had it right all along. Summary and Design
Choices now match it.

9486 said aggregation was 'only triggered when the user navigated to certain
pages', which its own Root Cause refutes: a mark-contacts-dirty change-feed
hook already existed pre-fix (confirmed at dc3ef42ab^). What was missing was
aggregation and persistence, not the trigger. Reworded.

9553 named handleIntervalTurnover in three places with no temporal
qualifier; #9714 removed interval turnover from master altogether, so the
function is gone. Time-scoped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(#136): disambiguate which 9486 file got the change subscription

Code Patterns listed both key files and then appended '(change subscription
+ debounce)', which reads as applying to both. The Solution says db-sync
changed only to make inProgressSync awaitable, and the diff agrees - three
lines, no subscription. Reordered so each file carries its own parenthetical.

Found by one coherence pass of three. By the protocol that is sampling noise
rather than a robust finding, but a single-pass finding was real once before
on this branch (9022), so they get read rather than dismissed. The other
single-pass finding this round was a genuine model error: its own rationale
said 'the first is not a contradiction of the second' and it reported the
pair anyway - the documented limit of a gate that proves quotes exist, not
that they conflict.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(#136): an off-by-one and a wrong file status (tasks-and-targets)

Both single-pass findings, both real - which is why single-pass findings get
read here rather than written off as sampling noise.

8772's summary says the short-circuit fires 'when the key count exceeds
500'. The guard is 'if (!params?.keys || params.keys.length <
MAX_QUERY_KEYS) return' with MAX_QUERY_KEYS = 500, so it fires at 500 or
more, not above 500. A reader implementing against this would put the
boundary in the wrong place.

10423 calls shared-libs/cht-datasource/test/target.spec.ts a modified
datasource target module; diff-tree at 622c625427 reports A.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(#136): 'Added/updated' hid four added files, and 'future' hid today

10423 wrote 'Added/updated mocha unit tests for ...' over a list of four
files that diff-tree reports as A, A, A, A. The hedge made the extractor
guess per file and made a reader unable to tell which. All four were added,
so the sentence now says so.

10480's Design Choices says the bubble counts 'Overdue' and due 'Today'
tasks, while the Solution said 'tasks due in the future are intentionally
excluded' - and a task due later today is in the future. Reworded to 'due
after today', with the due-today case stated explicitly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(#136): twelve more claims the exhaustive pass caught (tasks-and-targets)

Repeated ground and coherence passes over the same twenty-five drafts, on
the standing rule that recurrence proves a finding real while a single
appearance proves nothing. Every item below was checked against cht-core
or the issue text, not reasoned about.

Wrong facts:

- 10362 named the comparator `order-by-due-date-and-priority` in two
  sections. That is its test file; the export is orderByDueDateAndPriority.
- 11142 put FreetextFilterComponent in the tasks module. It lives in
  components/filters/freetext-filter/ and the Tasks page reuses it.
- 10436's Testing called two page objects and both e2e helpers new;
  diff-tree says both page objects were modified and only
  targets-helper-functions.js was added.
- 10623's Code Patterns credited reports and messages with dropping the
  duplicated lineage filter and omitted tasks.component.ts, which dropped
  its own removeUserFacility call in the same PR.

Summaries left behind by earlier corrections, the class this branch is
supposed to be closing:

- 9232 called a regression a missing feature. #9231 says multi-facility
  users could not view aggregate targets at all in 4.9.0.
- 10480 said the unread-count flow was generalised to carry the task
  count. setBubbleCounter still carries only reports and messages;
  getBubbleCounter spreads those and adds a task count off another slice.
- 8772 stated the short-circuit condition and then its inverse in the same
  parenthetical. Both true, unreadable together, and two passes read it as
  a contradiction.

Tense, where a file did not survive the 10140 epic:

- 10507 called libs/config.ts a helper it introduced and updated at once,
  and gave it a present-tense home the same draft denies.
- 10436 named it twice more unscoped.
- 10390 had no "paths are as of this PR" banner at all, despite ten of the
  twenty-one files its PR touched being target-interval.* names that exist
  nowhere in cht-core. It gets the banner; the vocabulary rewrite belongs
  to the data-access work.
- 10371's Code Patterns implied one component records both open and
  selection telemetry. analytics-filter.component.ts records only :open.

10480 also now says why a task due today counts: the due date is parsed
date-only, so it sits at midnight, and #3943 asks for exactly overdue and
due-today.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(#136): three more, all found by repeating the same passes

- 10423's Testing listed eight test files under one "Added". Six were
  added; the two e2e WDIO specs already existed and were modified. Both
  ground passes agreed on this one.
- 10324's Testing opened the same way and is worse: its PR adds no test
  file at all. Every spec named was modified, and the sidebar-filter spec
  was renamed rather than created.
- 9553's summary blamed "a CHT upgrade that changes target configuration".
  Root Cause blames the #9486 persisted-shape change and the code agrees —
  isStale is `(state) => !state || !state.targets || !state.aggregate`, a
  shape check that never reads configuration.

added-versus-modified is now five of the findings on this branch. It is
caught only when extraction samples the sentence, because deciding it
means scoping "Added X, Y and Z" across a coordinated list. A regex
attempt at that flagged 126 of 164 mentions, including one sentence
reading "(modified, not created)", so it was dropped in favour of running
more passes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(#136): bump lastUpdated on the three drafts edited today

verify-drafts compares lastUpdated against the file mtime; the previous
commit landed after the date rolled over.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(#136): two the fourth round of passes surfaced

- 10362's Domain Rationale said the implementation "centers on the task
  pipeline (new task-notifications service, tasks reducer, ...)" while its
  own Solution says the reducer is not consumed by the service and was
  only changed to import a comparator. The reducer comes out of the list.
  Same class as the rest of this branch: an interpretive section left
  asserting what the grounding pass had already disproved.
- 9232 wrote "added new translation keys
  (api/resources/translations/messages-en.properties)". The keys are new;
  the file is not, and the parenthetical reads as though it were.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(#136): 9553 had interval turnover reading the wrong interval

Solution said the migrated emissions are rewrapped "so
handleIntervalTurnover can read them against the active interval", while
Design Choices said the same function writes the PREVIOUS interval's
target doc.

Design Choices is right. handleIntervalTurnover returns early when
stateCalculatedAt falls inside the current interval, and otherwise
aggregates against calendarInterval.getInterval(monthStartDate,
stateCalculatedAt) — the interval the stale state belongs to — and stores
that as the target doc. Reading against the active interval is the one
thing it never does.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(#136): the 9553 interval fix introduced two unscoped anchor-era symbols

e1d0df4 corrected which interval handleIntervalTurnover reads, and in
doing so named calendarInterval.getInterval and stateCalculatedAt — both
real at the anchor, both gone from master because #9718 (also in this
batch) removed the interval-turnover mechanism entirely. The drift check
flagged them in three of the last four passes.

One scoping clause covers the sentence and points the reader at the 9718
draft, which documents the removal.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(#136): the five items from review 4845979803 (tasks-and-targets)

Each was re-derived from the PRs' own diffs and cht-core master before editing,
not taken on the reviewer's word. All five checked out.

9553 - the symptom was inverted. Issue #9552 reports a crash, not wrong numbers:
`Object.keys(state.targets)` in aggregateStoredTargetEmissions throws
`TypeError: Cannot convert undefined or null to object` because a pre-#9486 blob
is a bare targets map. Interval detection was never the defect --
handleIntervalTurnover already did `moment(stateCalculatedAt).isBetween(...)` and
`calendarInterval.getInterval(...)` at fe795fb^, and #9569 added no interval logic
at all (+1 line in rules-state-store.js, +9/-4 in target-state.js, rest tests).
Title, summary, Problem, Root Cause, Solution, Testing and Related Issues now all
tell the crash story; the e2e case is named ('should handle old format of the
rules-state-store') instead of being called a configuration change.

10436 - the harness attribution was backwards. This PR *removed* the mocha pieces
#10507 had added: config.spec.ts +0/-103, tsconfig.mocha.json +0/-9, .mocharc.js
+0/-2, libs/config.ts +0/-26, all deletions. webapp/tsconfig.spec.json is the
webapp-root karma tsconfig, is on master, and only gained sinon-chai types here.
`getValueFromFunction` was deleted outright (zero-hit on master), not folded --
its role is now getReportingMonth in rules-engine.service.ts, which this PR added.

10362 - `orderByDueDateAndPriority` is not a task-utils export on master.
task-utils exports only setTaskState; the comparator is at reducers/tasks.ts:15
and the service imports it from @mm-reducers/tasks. #10701 moved it back, its
description saying task-utils is for report SMS tasks, not rules-engine tasks.
The draft now records the round trip and names master's location.

10324 - the radio labels are both wrong and the contrast is imaginary. Both
filters render `targets.this_month.subtitle` / `targets.last_month.subtitle` =
"This month" / "Last month"; "Previous month" is zero-hit in messages-en and is
only the ReportingPeriod.PREVIOUS enum value.

10371 - the telemetry segment is `:reporting-period`, matching
collectFilterSelectionTelemetry('reporting-period') and the key its own Solution
already quoted.

Two more on these same drafts, from sweeping the class rather than the instance.
10371 carried the identical epic-rename misattribution filed only against 10324:
the e2e analytics/ -> targets/ rename was #10480 (bed454652) on master, not the
#10423 squash. And 10324 credited itself with the sidebar's `telemetryKey` input,
which it never touches -- #10371 added it; 10324 added userFacilities and
showFacilityFilter.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(#136): name which PR deleted libs/config.ts, in the draft that added it

10436's correction leaves 10507 as the only other draft describing
webapp/src/ts/libs/config.ts, and it attributed the file's disappearance to "the
epic" generically. It was #10436 specifically, later in the same epic, which also
removed the two mocha pieces 10507 lists in Related Files. Naming the deleting PR
makes the pair agree and gives a reader one hop to the whole story.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(#136): four contradictions the gate found outside the review's five

Re-running the full gate over the reworked branch surfaced these on drafts the
round-4 review did not name. Each adjudicated against cht-core before rewriting.

9486 - three passes, because the first two fixes were themselves wrong. The
summary said targets were computed "only ... when visiting specific pages", which
its own Root Cause contradicts with two 120s ensure-freshness debounces
(`ENSURE_FRESHNESS_SECS = 120` at dc3ef42ab^, used twice). Correcting that to "a
120s debounce" then contradicted the same line's "two separate" -- and correcting
*that* left Problem claiming nothing ran on incoming changes while Root Cause said
the hook called updateEmissionsFor per change. At dc3ef42ab^ that function only
does `rulesStateStore.markDirty(contactIds)`: it invalidates, it does not
recompute. Problem now says exactly that.

9705 - the Problem opened by locating the swallowed error on the write, while the
summary, the next sentence, Root Cause, Solution and Design Choices all locate it
on the read that precedes the write. The read is right; the opener is now neutral
about which call failed.

10390 - Domain Rationale said "all changed files are shared-libs/cht-datasource
plus one API controller", but the PR also changes api/src/routing.js, adds
integration tests under the top-level tests/integration/ tree, and touches
.mocharc.js and package.json. Reworded to state the scope without under-counting.

8932 - the title called the flashed strings "empty states" while Root Cause shows
both are gated on the has-items flag being true (`hasTasks`, `hasContacts`), which
makes them end-of-list messages, the opposite of an empty state. Title and the two
tags follow.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants