chore(memory): promote strong-fit forms-and-reports drafts from memory-pipeline for review - #122
chore(memory): promote strong-fit forms-and-reports drafts from memory-pipeline for review#122Hareet wants to merge 23 commits into
Conversation
551acb2 to
e90aef1
Compare
|
Needs to be rebased with main after #119 is merged |
|
Heads up, this one currently has merge conflicts with its base and will need a rebase before it can merge. |
1979c05 to
6a2742a
Compare
sugat009
left a comment
There was a problem hiding this comment.
Content review. Prose fidelity is high across a wide sample (10022, 10246, 10730, 8746 all verified faithful). Blockers:
- issue (blocking): identity keys record the PR number on 25 of 47 drafts (verified);
8740closes no tracked issue. - issue (blocking): 6 duplicate clusters (13 files): issue 8745 = [8746, 8748, 8752], 9429 = [9434, 9436], 9604 = [9608, 9610], 9835 = [10022, 10246], 10040 = [10071, 10099], 10041 = [10180, 10200]. Plus near-duplicate content:
10922(#10904) and11116(#10700) distill the same attachment-routing feature. - issue:
related_issues: []empty on every draft;domainFit: strongon every draft. Forced picks:9512(route guard across seven*.routes.ts, no form-engine code),9513(once-a-day display gating),11023(geolocation.service.tsonly),9641(API startup resilience). Borderline:9592(training-materials page that does include training forms). - nitpick: classifier/seed reasoning leaks into
## Domain Rationaleof the 8745 cluster ("seed-3 principle"). - nitpick: category vs slug/PR type:
9414isbugbut slugfeat9413;9840isfeaturebut the PR is a fix (its key 9844 is correct).
Clean bill: no secrets, no PII, schema 100% valid.
| category: bug | ||
| domain: forms-and-reports | ||
| domainFit: strong | ||
| issueNumber: 8748 |
There was a problem hiding this comment.
issue: 8746/8748/8752 are three PRs (base + two backports) for one issue #8745, distilled as three separate memories; they should collapse to one. The "## Domain Rationale" here also leaks the internal "seed-3 principle" phrasing.
| --- | ||
| id: cht-core-8119 | ||
| category: improvement | ||
| domain: forms-and-reports |
There was a problem hiding this comment.
issue (domain-fit): this is an Angular canDeactivate route guard wired across seven *.routes.ts (about/analytics/contacts/messages/reports/tasks); it is navigation plumbing, not forms-and-reports.
| category: feature | ||
| domain: forms-and-reports | ||
| domainFit: strong | ||
| issueNumber: 11116 |
There was a problem hiding this comment.
issue: near-duplicate of 10922 (both route Enketo attachments to the owning sub-doc, same fixtures); 10922 closes child #10904, 11116 targets epic #10700.
…ly, forms-and-reports) 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>
…rts) Per sugat009's review on #122: collapse all 6 flagged clusters plus the 6 old-vs-new collisions the relink surfaced (12 total) to one memory per issue with source_prs[] — backport sets 8745/9429/9604, layered features 10040/10041, and folds into the curated issue-keyed memories for 10133, 8225, 8306->8308, 8806, 9227, 9301. The 10922/11116 attachment-routing near-dup collapses to the child issue #10904 with the epic #10700 noted in prose. 16 files removed. Cross-domain: the #9835 pair (10022, 10246) moves to the contacts canonical that owns the issue; the misdomained smsparser draft (10730) drops in favor of messaging's #10729 memory; the curated 10443/10509 memories absorb the infra (#10445) and contacts (#10570) branch PRs. 8740 keeps issue #7462 (title names it; the closed Enketo-uplift issue matches the work) rather than dropping as no-issue. Category fixes per issue labels: 9414 and 9840 -> improvement. Forced domain fits re-annotated weak (9512, 9513, 11023, 9641); 9592 stays strong. Reviewer/process narrative and classifier phrasing scrubbed. All 47 mappings verified against the live cht-core API (0 mismatches); validate-schema 95/95; no duplicate issueNumbers. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
573ca6b to
849aa01
Compare
Companion to the forms (#122) and tasks (#123) seeders' cross-domain dedup — this corpus canonically owns their issues, so the PR provenance is recorded here: the #9835 memory gains the report-side PRs (#10022 ReportQualifier groundwork, #10246 reported_date fix), and the #10344 memory gains #10432 (targets-by-contact-id datasource support). The 10570 draft (#10509, attachments in contact forms) is removed: the forms corpus's curated 10509 memory owns that issue and now records PR #10570. validate-schema 91/91; no duplicate issueNumbers. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Companion to the forms (#122) seeder's cross-domain dedup: the curated forms-and-reports memory for issue #10443 (default training forms missing from Docker images) lives on main and now records PR #10445 in its source_prs, so the duplicate draft here is removed. validate-schema 107/107; no duplicate issueNumbers. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rts) Companion to the tasks (#123) seeder's cross-domain dedup: this corpus canonically owns issue #9974 (open contact edit form from task), so the duplicate draft dropped there is recorded here — PR #9975 added to source_prs with a one-line account of the shipped mechanism. validate-schema 95/95; no duplicate issueNumbers. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Proposal: a first-class
|
sugat009
left a comment
There was a problem hiding this comment.
Content re-review (post-rework). Identity/dedup are clean. Remaining:
- issue (accuracy):
9227names a non-existent XPath function (inline). - issue (domain): the createReport / report-update drafts (
10064/10071/10180) extend the cht-datasource library and belong in the agreeddata-accessdomain (inline on10071). - nitpick (domainFit):
9592isstrongbut is the same training/navigation class as itsweaksiblings9512/9513(inline). - nitpick (leakage):
11165Domain Rationale scaffolding; strip. - (
10922/11116: only a minor gap — the contacts-side child issue10903has no draft; listing11116insource_prsis defensible.)
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.
The largest cross-cutting item, moving the cht-datasource library-extension drafts to a first-class
data-accessdomain + a weightedsecondaryDomains[]field, is in a separate detailed comment on this PR.
| @@ -6,17 +6,20 @@ subDomain: enketo | |||
| issueNumber: 9227 | |||
There was a problem hiding this comment.
issue (accuracy): this draft (Solution section, ~L30) names the XPath function cht:luhn-check, but the real function is cht:validate-luhn (registered in PR #9220 as 'cht:validate-luhn': luhn; current webapp/src/js/enketo/medic-xpath-extensions.js and the CHT docs use it, added 4.10.0). cht:luhn-check never existed — an agent grepping the corpus would find a non-existent function. Please rename throughout.
| --- | ||
| id: cht-core-10040 | ||
| category: feature | ||
| domain: forms-and-reports |
There was a problem hiding this comment.
issue (domain): this PR (and 10064/10180) touches only shared-libs/cht-datasource — createReport/report-update library API. Per the team-agreed data-access domain (#86), these library-extension drafts belong in data-access with secondaryDomains: [forms-and-reports], not primary forms-and-reports. See the detailed data-access proposal comment on this PR.
| id: cht-core-9598 | ||
| category: feature | ||
| domain: forms-and-reports | ||
| domainFit: strong |
There was a problem hiding this comment.
nitpick (domainFit): graded strong, but this is a training-materials/navigation page — the same class as 9512/9513, which are weak. Re-grade to weak for consistency.
9227 — the reviewer is right and the case is stronger than the comment.
`cht:luhn-check` is absent from every ref, not just master:
git log --all -S'cht:luhn-check' --oneline # empty
git log --all -S'cht:validate-luhn' --format='%h' # 3c2b140a3, one commit
git tag --contains 3c2b140a3 | sort -V | head -1 # 4.10.0
Renamed throughout. Reading the source turned up two the review did not
cover: Testing claimed an empty-string edge case that none of the sixteen
tests under describe('#validate-luhn()') exercises, and the usage example
dropped the real optional expLength argument. Both corrected, and the draft
now notes that the same commit registered cht:strip-whitespace, which is why
spaced input passes.
9592 — kept at domainFit: strong, against the review. The premise is that it
is the same class as 9512/9513. 9512 is a canDeactivate guard across eight
*.routes.ts; 9513 is a localStorage date check in training-cards.service.ts;
neither touches form-engine code. 9592 adds
training-cards-form.component.ts, which builds an EnketoFormContext, calls
XmlFormsService.get() and FormService, and implements renderForm() and
saveForm(), plus three real XForm fixtures. Grading it weak would make the
corpus less consistent, not more. The rationale now cites the component so a
reader can check the call instead of trusting the grade.
11165 — stripped the scaffolding ("so no pitfall redirects apply"). Swept the
corpus for the same shape; it was the only one. The "least-bad home"
sentences in 9512, 9641 and 11023 are ordinary rationale prose and stay.
9512 — its Domain Rationale said the guard is wired across "seven" feature
modules, which is the phrasing from the round-1 review comment, whose own
parenthetical lists six. It is eight, and the draft's own Solution enumerates
all eight, so the draft contradicted itself:
git diff-tree --no-commit-id --name-status -r -M 49dcd919a | grep -c routes.ts # 8
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Every one re-derived from cht-core before editing, because three of the
gate's own findings turned out to be wrong (see the next commit's note and
the tooling branch).
Fabricated symbols, with the real name established from the tree:
8806 ValidationResult / validation_result.js — the PR DELETES that file
(D in its own diff) and ADDS validation_utils.js; ValidationResult
appears nowhere. isSubmittedInWindow is fictional too; the real
validators are exists, unique, uniqueWithin, validPhone, uniquePhone,
isISOWeek, isAfter, isBefore. Its Solution also still described the
architecture the PR removed, contradicting Design Choices.
10071 createReport / 10180 updateReport — the API is Report.v1.create and
Report.v1.update inside a namespace; createReport survives only as a
test stub name. 10180 also listed test/input.spec.ts, added on no ref.
8759 contact_by_parent — the view is contacts_by_parent. The draft copied
the typo from issue #8074, which is worth knowing about issue bodies.
9301 user.summary — the binding is userSummary, and it gates form
visibility, not data entry.
9340 "appearance: number tel" — it is "numbers tel"; numbers is what makes
the field render as input[type=tel].
10784 quoted new CustomEvent('before-save', …) as the fix. That string is in
no commit; the PR imports enketo-core's factory and calls
events.BeforeSave().
10922 findBinaryNodeByFilename — real name findFileNodeByFilename, and it
matches [type=file]: Enketo's Nodeset.setVal rewrites file-widget
nodes from binary to file on upload.
10922 also asserted, in present tense with stale: false, a mechanism on no
branch reachable from master:
for s in 0df57c664 cc34e08664 e88c88361; do
git merge-base --is-ancestor $s origin/master && echo YES || echo NO; done # NO NO NO
It now opens with a banner naming the three feature branches and is
stale: true. Its Related Issues also claimed #10904 was closed by this PR;
the issue is still open, which is consistent.
added-vs-modified: 10064 called three test files added — all three are M and
the PR's only added file is shared-libs/lineage/src/index.d.ts. 8759, 8806
and 8826 each described a modified test file as added.
9608's mechanism was inverted: the pre-fix validators were too strict
(parseInt(value,10) === value against SMS-parsed strings, so integer always
returned false) and the fix RELAXES five predicates to == with an explicit
eslint-disable. Its backport sentence is left byte-identical — it is true.
9974 described the issue's proposal rather than the shipped code: modifyContent
is a partner-authored task-config callback, only content.edit_id is set, and
the routing is in tasks-content.component.ts::performAction.
10071/10180 are epic children of #10083 and now carry a Provenance section.
Their source_sha values are restored, not "corrected": both are exactly what
GitHub reports as the PR's merge_commit_sha, and are missing from a clone only
because the epic squashed them away.
8740 was keyed to #7462 ("Make code for Enketo forms reusable outside
cht-core"), a different ticket; the epic's ticket is #7599. Re-keyed and
renamed so the filename token stops contradicting the frontmatter.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sweep of all 41 drafts against cht-core and the linked issue bodies. Thirty-
five carried at least one defect; the review list covered four of them.
Inverted mechanism — the draft describes the wrong fix:
10304 said the deselect handler was corrected. deselectAllReports() is not
in the diff. areAllReportsSelected() compared the selection against
reportsList — the RENDERED page — so with more selected than rendered
the checkbox drew unchecked and the template's ternary re-ran
select-all. That is why #9739's repro says "at least 50 reports".
Five sections were wrong.
10949 said the validator strips XML comments so comments mentioning
<!DOCTYPE are not flagged, and listed "no false positives" as tested.
There is no comment stripping, and the PR's own test asserts such
forms are REJECTED. Four sections were wrong; the check is
deliberately comment-blind and now says so.
9641 described a per-form try/catch that skips the broken form. There is
no loop: updateAll() moved into its own try/catch that logs instead
of process.exit(1), and still aborts at the first bad form. The draft
now records that limitation, which is the useful part.
8656 inverted the symptom entirely — this is "xpath extensions tests fail
in my timezone", fixed by pinning Date.prototype.getTimezoneOffset in
a beforeEach, not a runtime inconsistency between extensions. Retitled
and renamed, and category chore -> improvement (chore is not in the
schema enum).
9414 said the listener "never fired"; the issue reports a stale-by-one read
in enketo-core's CI only. The macro-task fix is in the karma spec, not
the e2e spec.
11165 described a guard that blocks conversion. The widget cannot gate the
library: it lets the conversion happen, clears the output, and
re-asserts on the next tick to beat the library's own blur handler.
Attribution to files the PR never touched:
10133 put the _all_docs-with-attachments call in generate-xform.js; it is
forms.js.
10509 said it reused the enketo service's extraction logic. That service is
not in the PR and the originals are private, so the logic was
re-implemented — which is why #11256 later merged the paths.
9840 credited enketo.service.ts / form.service.ts with extension-lib
injection; it goes through the cht-form stub datasource. Those files
changed because EnketoFormContext became an interface.
9755 claimed a freetext-index fallback "for search strings containing
whitespace", in six sections. No such fallback exists; the keyed-vs-
range split lives in cht-datasource and keys on a colon.
8336 pointed at webapp/src/js/enketo/widgets.js, which #10269 does not
touch and which has nothing to do with xforms-value-changed — that is
enketo.service.ts:327 and the transformer XSL. Also given a
source_prs entry: it had no PR reference in frontmatter at all, which
is why its anchor would not resolve, even though its prose names
#10269 and its "78 files" claim is exactly right.
10814 called extensionLib a method on XmlFormsContextUtilsService; the PR
removed every public method in favour of an async get() factory.
stale-as-written: the drift epic here is cccce201e refactor(#10700): re-write
Enketo form save workflow (#11256), which deleted contact-save.service.ts and
enketo-translation.service.ts. 10509, 10784 and 10922 are time-scoped against
it rather than silently corrected to master's shape. Nothing in this batch
records that rewrite, because the #10700-keyed draft was the one dropped in
the round-1 dedup.
10937 category improvement -> feature: issue #9339 is Type: Feature and the
commit is feat(#9339).
10290, 10756 and 8949 were checked and left alone.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Repeated passes over the corrected drafts, which is the point of the count.
verify-drafts --online, 3 blocking + 1 weak cross-reference, all introduced by
this round's own edits:
10071/10180 cited #10083 in Related Issues glossed as "the epic PR whose
squash carries this work" — true of the PR, but it is a PR cited
as an issue and the gloss shares nothing with its title. Now
labelled PR #10083 and glossed with its real subject.
10071 cited #10038 as "the broader report-creation feature". #10038 is
"To have API that can create places" — the PLACE half of the same
datasource work, not the report half. Re-glossed.
8740 glossed #7674 as "Enable excludeNonRelevant in the Enketo
config". That is the fix; the issue is "Answers to non-relevant
questions in forms are not immediately cleared with new Enekto".
ground-claims, second pass. The one that matters:
10509 the previous commit justified the duplicated extraction by pointing at
enketo.service.ts's private processFormAttachments /
buildBinaryAttachmentData. Those did not exist at this PR's anchor:
git log --all -S'processFormAttachments' --format='%h %ci'
# ec882d703 2026-07-17 ← five months AFTER d09d656cb8
At the anchor the logic was inline in xmlToDocs with no callable
helper, which is the real reason the contact path re-implemented it.
An anachronism introduced while fixing something else — exactly the
failure this exercise is about, committed by the person fixing it.
8806 put pupil's validator map in pupil.js; it is validator_functions.js,
looked up by validator.js.
8759 "added/updated" for a file that is only modified — the hedge read as
"added" to the probe, and to a reader.
10756 dropped "Full Enketo regression suite … passed 103/103" — a run-log
artefact naming a path (tests/karma/js/enketo) that does not exist.
Un-greppable literals rewritten so they can be checked rather than trusted:
10443 "training:admin:1234" was an instantiation; the code has the template
literal training:${USERNAME}:1234.
9513 "training-cards-last-viewed-date-<username>" likewise; the constant is
STORAGE_KEY_LAST_VIEWED_DATE, suffixed by getLocalStorageKey().
8336 config/*/forms/ and tests/**/forms/ are globs, not paths; replaced
with the real trees.
9340 instance::cht:unique_tel stays — it is an XLSForm column header and
real — but the draft now also names the greppable artefacts it becomes
(cht:unique_tel in the instance, data-cht-unique_tel on the question)
and says why the header itself cannot be found in the tree.
10071/10180 unbackticked merge_commit_sha, a GitHub API field the probe was
reading as a cht-core symbol.
lastUpdated on 10290, 10756 and 8949 set to their real last-edit date rather
than today: their content was not changed this round, and the stale-timestamp
warning was inherited from an earlier one.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Each side settled against cht-core rather than reasoned about. One of these
(9340) was found by the FIRST coherence pass and I failed to hand that report
to the sweep, so it survived a whole round — worth recording as a process miss
rather than quietly fixing.
9340 Domain Rationale said "the contact duplicate-check is a secondary
capability of the widget, not the subject of the change", while the
summary says the PR makes the dup-check opt-in. The dup-check IS the
subject. Rewritten.
10842 summary and Problem both said arrays were "always inserted into repeat
groups". Pre-fix, an array aimed at an ordinary field was refused:
git show 018037e56^:webapp/src/js/enketo/widgets/android-app-launcher.js
# if (Array.isArray(value)) { console.debug(… "value is an array"); return; }
Nothing was written at all. Repeat insertion was only ever available
through the android-app-value-list appearance.
9301 Code Patterns said the summary is "loaded once per form session";
Design Choices said the cache avoids recomputing it every time a form
opens. The cache is a CacheService entry invalidated by
ContactChangeFilterService.isRelevantChange — it outlives a session
entirely. Code Patterns was the stale side.
10133 Problem called the update-path read "the same" read as the startup one
while Root Cause calls them two separate reads in two files. Both are
true of different things; disambiguated.
8308 Design Choices "added draw and file-upload integration tests" vs
Testing "E2E test for photo upload forms (updated)". Both correct —
different files (the integration specs are A, the e2e spec is M) — so
this is a checker false positive. Rewritten anyway to name the files:
if a checker misreads a sentence, a reader will too.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both are the same failure mode: correcting one section and leaving its sibling
asserting what was just disproved. Worth naming rather than folding into an
earlier commit, because the count of rounds is the honest signal here.
10071 I re-glossed #10038 in Related Issues as the place-creation sibling
(it is "To have API that can create places") but left Design Choices
calling it "the broader create-report feature this work feeds into".
The report half is #10040, which is this draft's own issue.
10509 I rewrote Code Patterns to say the extraction was inline in xmlToDocs
with no callable helper — and left Root Cause still saying it "lived
in private methods there". The private methods arrived with #11256,
five months later.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
8336 My own previous commit replaced two glob patterns with a list of
config trees — and invented two of them. #10269 touches
config/default/forms (22 files), config/demo/forms (21) and
config/covid-19/forms (10). There is no config/default-bs or
config/standard in its diff:
git diff-tree --no-commit-id --name-only -r 5fcfbcbafb \
| cut -d/ -f1-3 | sort | uniq -c | sort -rn
Replacing an ungreppable glob with a wrong path list is a worse
failure than the glob was. Now states counts and names real files, so
the claim is checkable instead of merely well-formed.
9227 My rewritten Testing section quoted describe('#validate-luhn()'), a
literal that `git grep -w` can never match. Points at the greppable
cht:validate-luhn instead — the same blind spot the docs already
record for placeholder literals, walked into while fixing something
else.
9340 My note about the XLSForm column header attributed cht:unique_tel to
phone-widget.js. It is not there: cht:unique_tel appears in the
generated XForm instance, and what the widget reads is the
data-cht-unique_tel attribute (phone-widget.js:61). Both now named in
the right place, which is the whole point of the sentence.
8759 "The original `with-same-parent` naming was ambiguous" — that name is
in no commit on any ref; it existed only in review discussion.
Recording a dead name as though it shipped misleads a reader, so the
rationale now argues from what the filter does rather than from a name
that never existed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
10071 Design Choices justified the local work as "parity with the remote
context", while the draft's own Problem says the remote side had no
create implementation either. Both halves were added by the same
epic, so this is one side of a paired addition, not a catch-up.
10509 Third round on the same sentence. I corrected Root Cause, then Code
Patterns, and Design Choices still said the enketo service's version
was "private to that service" — the framing that was wrong in the
first place, since there was no method there at all until #11256.
Recording the round count rather than smoothing it over: this is the
draft that shows why one clean pass proves nothing.
8740 "enketo-core's `relevant.js`" reads as a repo path and is reported
ungrounded on every pass, because it is a third-party file. Says
"enketo-core's own relevance module" instead, and points at
webapp/patches/enketo-core+7.2.5.patch — a real path in this repo —
for where CHT actually overrides it. The claim is unchanged; it is
now checkable.
8336's remaining finding needed no draft change: "create" inside the fixture
name ngo-create.xlsx was being read as a create verb. Fixed in the tooling
instead (memory/draft-verification d62a907) with regression tests.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… we broke
The important one first.
**10071: an earlier commit on this branch replaced true claims with false ones.**
The sweep concluded that `createReport` was fabricated and that
`src/qualifier.ts` "was never part of this work", both checked against the
epic squash — because at that moment the child PR's own merge commit was not
in the clone. It is now, and it says the opposite:
git diff-tree --no-commit-id --name-status -r -M cab214534 d40e65bae7
# M shared-libs/cht-datasource/src/local/report.ts
# M shared-libs/cht-datasource/src/qualifier.ts
# M shared-libs/cht-datasource/test/local/report.spec.ts
# M shared-libs/cht-datasource/test/local/person.spec.ts
git show d40e65bae7:shared-libs/cht-datasource/src/local/report.ts | sed -n '81p'
# export const createReport = ({
`createReport` is real at this PR, taking a `ReportQualifier` and rejecting
`_rev`; the qualifier.ts change is one line, exporting `ReportQualifier` so
the adapter can name it. The #10083 squash then renamed the operation to
`Report.v1.create`, moved it into a `v1` namespace and replaced the qualifier
with `Input.v1.ReportInput` from a new `src/input.ts` — none of which is in
this PR's diff.
So the original draft was right and we corrected it into being wrong. The
draft now records both views and says which is which, the way the 10140 epic
children on #123 do. The flat statement "there is no `createReport` symbol
anywhere in cht-core's production code" is gone; it was false.
This is the exact laundering this exercise exists to prevent, and it happened
here because an anchor moved between passes: the clone acquired the child
commit mid-run, so passes before and after disagree about which tree to judge.
Worth knowing that an unresolvable anchor is not a stable property of a clone.
Also:
8336 cited ngo-create.xlsx as a regenerated fixture; it is `A`, the one
file the PR adds. Cites two genuinely regenerated fixtures instead.
8740 a second `relevant.js` in Design Choices, sibling of the one already
reworded — the same third-party path in the same draft, missed first
time because only one occurrence was quoted.
10756 said the widget parses `cht:unique_tel`. It parses the rendered
`data-cht-unique_tel`; `cht:unique_tel` is what pyxform emits into the
XForm instance.
9340 "behavior is selected from appearance … rather than the field type"
was too absolute. `_init` reads
`$wrapper.attr('data-cht-unique_tel') === 'true' || deprecated.isDeprecated($wrapper)`,
so the legacy shape still turns dup-checking on through the second
branch — which is why the draft can say legacy behaviour is preserved
without contradicting itself.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three ground passes and three coherence passes on frozen bytes turned up
seven things, so this is not yet the clean run. Three of the seven are
collisions between my own earlier fixes.
Ground:
10071 `entities` still listed shared-libs/cht-datasource/src/input.ts.
That file is the epic's, not this PR's — the PR changed four files
and input.ts is not among them. Dropped; the Related Files section
already explains that input.ts arrived with the squash.
8740 a THIRD `relevant.js` in the same draft, this one in Solution. Two
earlier rounds each fixed one occurrence and left the others,
because only the quoted sentence was looked at.
8746 `form.properties.json` is a filename pattern, not a path — nothing is
called that. Names the real fixture,
tests/e2e/default/tasks/forms/home-visit.properties.json.
9641 `form:broken` never appears in the source; the test builds
``form:${formName}`` with formName = 'broken'. Quotes the template.
Coherence — all three of these are mine:
9340 I added a Code Patterns note that the legacy `type: tel` shape keeps
always-on dup-checking through `deprecated.isDeprecated`, and left
Domain Rationale saying the dup-check is simply "opt-in after it".
Flagged in all three coherence passes. Domain Rationale now states
both paths.
9227 I added "the same commit also registered `cht:strip-whitespace`" to
Solution, and left Design Choices justifying the file placement
"since it is a single function".
10922 Design Choices says routing is by XML position "rather than flat
filename-to-doc matching", while the known-limitation sentence
describes a filename lookup misrouting files. Both are true of
different steps: the ancestor walk picks the owner doc, but
findFileNodeByFilename picks the node the walk starts from. Said so.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Ground has now been clean three passes running; coherence had one pass in
three that was not, which is the whole argument for the pass count.
10071 Problem said "person and place already had a full create path".
Person did, on the epic branch — at this PR's parent cab214534 there
is Person.v1.createPerson, api/src/controllers/person.js's
createPerson, and postResource('api/v1/person') in remote/person.ts.
Place had none, which is why #10038 is still open as the sibling
half. Half the sentence was right, which is what made it survive
eleven passes.
8826 Root Cause's "no mechanism to carry a per-field duration through form
generation" sat beside its own note that the old note-based timer
read a duration off the note's value, and beside Design Choices
calling the new column a mirror of that prior capability. Internally
consistent if read carefully, and read as a contradiction by the
checker — the same call as 8308 last round: if a checker misreads a
sentence, a person will too. Scoped the "no mechanism" to form
generation and said plainly that durations were already configurable
the one way that needed no generation support.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Ground was clean three passes running (g11-g13, 0 ungrounded each); the next
three found four more. That is the sampling, not a regression — same drafts,
different claims drawn each time.
10071 my own sentence from the last commit quoted
`postResource('api/v1/person')`. The real call takes the context
first — postResource(remoteContext, 'api/v1/person') — so the literal
matches nothing. Names the symbol and the route instead of inventing
a call form. Third time a fix of mine has introduced an ungreppable
literal.
10071 Design Choices said #10099 "reused the existing person/place create
architecture" while Problem now says place had none. Person's was
standing on the epic branch; place's was not. Flagged by two of three
coherence passes.
8225 three enketo-core module paths (src/js/relevant.js, src/js/form.js)
read as repo paths. Says "enketo-core's relevance module" and "form
module", keeping webapp/patches/enketo-core+7.2.5.patch — a real path
here — as the anchor a reader can actually open.
10917 "renaming the widget from HiddenFieldList/hidden-field-list.js to
HiddenGroup/hidden-group.js". hidden-field-list.js is in no commit on
any ref: the PR adds hidden-group.js outright, and the narrower name
existed only in the review iterations. Recording a name that never
landed sends a reader looking for a file that was never there.
10133 summary said "a single _all_docs call" while Root Cause says two
separate reads in two files. Names both paths.
Two findings deliberately NOT acted on, because the drafts are right:
10922 "PR #11116 … updated downstream contact rendering —
contact-save.service.ts, format-data-record.service.ts,
contact-photo.component.ts, contacts-content.component.ts". The probe
judged that at #10922's anchor, where none of those files exist. But
the sentence credits #11116 explicitly, and e88c88361 touches all
four (contact-photo.component.ts among the files it adds). The
enumerate-claims layer already declines to infer a status when
another PR is credited; the path probe does not yet apply the same
rule.
8806 a contradiction reported with the literal title "placeholder" and two
unrelated quotes — the checker emitted a finding with no rationale.
lastUpdated set to 2026-08-10 across all 41, folded in here rather than left
for a follow-up: a metadata-only commit would reset the convergence streak for
no content reason, which is how the last round lost its clean ground passes.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Passes g17-g19 and c17-c19 all ran after 1c7b4d2, so their findings were about committed bytes and nobody acted on them. g19 and c19 came back clean and the run stopped there, but c17, c18 and g18 had each surfaced something on that same content first. Clean-at-the-end is not the same as converged. 10922 the epic-work sentence named `contact-photo.component.ts` as a bare filename. PR #11116 really does add it, at webapp/src/ts/components/contact-photo/contact-photo.component.ts, which the Related Files list already gives in full — but the bare name resolves nowhere at this draft's anchor, so a reader greps and finds nothing. The sentence now describes the component and leaves the path to the list that already scopes it to #11116. 10922 Design Choices asserted the ancestor walk "ensures attachments land on the structurally-correct owner" and then, in the same paragraph, gave the limitation that defeats exactly that: the walk starts from a node found by filename, so two same-named files start from the same node and land on the same sub-doc. Scoped the guarantee to the caveat it already states. 8656 Root Cause claimed the `asMoment()` fallthrough "re-parsed the raw input instead of returning the rMoment it had already built, so the two paths could disagree", while Problem said no deployed behaviour was wrong. The source settles it for Problem: the branch is `return moment(r)` with `const rMoment = moment(r)` in scope and `r` never reassigned between them. Same parse, same string, twice — redundant, not divergent. Reworded Root Cause and the Solution's description of the tidy-up. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…concerns The review asked for `10064`/`10071`/`10180` to move to a `data-access` primary domain with `secondaryDomains: [forms-and-reports]`. The decision to defer that — taken on the reviewer's own recommendation to ship the enum value and the new field as one coordinated taxonomy change rather than through a content PR — lived only in the review thread, so a reader of the corpus saw three cht-datasource extenders keyed `forms-and-reports` with nothing explaining why. Each of the three now records it in Domain Rationale: the files are entirely shared-libs/cht-datasource, that makes them library extension rather than consumption, the re-key was requested, and it is deliberately not made here. `10071` had no Domain Rationale section at all — the one draft the reviewer's domain comment was actually filed against, and the section where the answer belongs. It has one now. It is the only machine-distilled draft missing it; the other ten without the section are the hand-authored files, which is the two-schemas item already flagged as not blocking. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three ground and three coherence passes over the frozen bytes of 789f817. Four of the six are the corpus; two are probe artifacts fixed by making the draft more precise rather than by arguing with the gate. 10064 MY error, flagged by all three coherence passes. The Domain Rationale I added in 789f817 said the files are "entirely shared-libs/cht-datasource". The diff also carries api/src/controllers/report.js, shared-libs/lineage/src/index.d.ts, two webapp files and integration tests — which its own Solution section already spelled out. Reworded, and it now notes that the review's "touches only cht-datasource" premise is weaker for this draft than for 10071/10180. 9608 Root Cause said the integer predicate "returned false for every input" while Design Choices said loosening `===` to `==` "preserves behaviour for callers already passing numbers". Both cannot hold. The source settles it against Root Cause: `integer: (allValues, value) => parseInt(value, 10) === value`, so a numeric 5 was already true and only SMS-parsed strings failed. Scoped the claim and stated why numeric callers are unaffected. 10842 The summary conditioned the join on "the target field is not a repeat" while the Solution says no repeat detection exists — the join fires on any all-primitive array, and repeats are unaffected only because their helpers pass one element at a time. Summary now describes the trigger the code actually uses. 9641 `--skip-validate` is a cht-conf flag, probed against cht-core where it can never appear. It is real (cht-conf src/cli/usage.js:71); the draft now says whose flag it is. 10071 "a postResource call ... in `src/remote/person.ts`" is true at the parent commit cab214534:14, but the partial path resolves nowhere. Full path. 10917 "The widget is registered in webapp/src/js/enketo/widgets.js" is true — widgets.js:34 is `require( './widgets/hidden-group' )`. The probe looked for the `HiddenGroup` symbol, which is not how registration works here. The draft now says so, which is the more useful sentence anyway. Not fixed: 10784 quotes `import events from 'enketo-core/src/js/event'`, a real line at enketo.service.ts:6. It is a package specifier, not a repo path, and the probe cannot tell the difference. Left as written and disclosed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both from the second convergence set; ground came back clean three passes running
(g23-g25, 0 ungrounded each) and `verify-drafts --online` cleared all 41 with 0
unverified, so these two are what is left.
10784 The summary blamed the `end`-timestamp bug on the jQuery trigger not
reaching a native listener, while Root Cause names two defects and the
event name is the first of them. The diff bears that out —
`$('form.or').trigger('beforesave')` became
`form.view.html.dispatchEvent(events.BeforeSave())`, changing both the
dispatch mechanism and the event identity. Summary now carries both.
10917 Testing said "Added Karma unit tests (…hidden-group.spec.ts)" and then
"Neither the spec nor the fixtures were newly created here". Both are true
of different files and the second reads as denying the first.
`git show --name-status 23225a57d7`: the Karma spec is `A`, the e2e spec
and both db-object fixtures are `M`. Says which is which now.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…_issues
10071 Code Patterns said the report create chain mirrored "the existing
person.ts and place.ts implementations" while Problem says place had no
create path yet and that #10099 added it. Person's was standing at the
parent commit cab214534; place's was not. Corrected to name person only
and point at Problem.
This one is mine twice over: the same contradiction was flagged by the
first convergence set, I fixed the postResource path on this draft in the
same round, and left this line untouched. A finding read is not a finding
fixed.
10922 Frontmatter carried `related_issues: []` while the Related Issues section
lists three. Populated with the two that are genuinely related — the
#10700 epic and the #10903 sibling — leaving out #10904, which is the
draft's own issue.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three from the fourth convergence set. Ground is clean six passes running
(g23-g28) and the online audit cleared all 41; coherence is the only channel
still finding anything.
10133 Two, both in the same draft.
The summary blamed the timeouts on both reads. Root Cause is more precise
and correct: the `_all_docs` batch read is the one that hangs
(apache/couchdb#2210), while the per-doc `get` on the update path was
expensive, not hanging. Summary now says which is which.
The Solution said the attachments "read and saved" are the XForm XML
"plus `model.xml` and `form.html`", which contradicts Design Choices
skipping everything non-XML. Reading the code settles it: `getFormDocs`
fetches only the attachment named by `getXFormAttachmentName`, and
`model.xml` / `form.html` are outputs generate-xform.js writes back
(:243, :247). Read and written are now separate claims.
9340 Design Choices said validation and the duplicate check "can be enabled
independently". The PR's own fixture shows otherwise: the new field is
`type: string` with `appearance="numbers tel"`, which always validates
format, and only the uniqueness lookup is opt-in via
`cht:unique_tel="true"`. There is no switch for the format half.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Design Choices said the fix belonged in enketo-core "since the behavior was incorrect regardless of CHT-specific logic", while Solution says the patch special-cases the `inputs` group. Both cannot be the reason. The patch settles it. webapp/patches/enketo-core+7.2.5.patch carries the comment `// CHT-CORE PATCH` / `/inputs is ALWAYS relevant #4875` and matches `/^\/[^/]+\/inputs$/` — a hard-coded CHT form convention, not upstream-correct behaviour. The real reason to patch enketo-core is that relevance is evaluated there, so it is the only layer where the branch can be kept enabled; and being CHT-specific is exactly why it sits in webapp/patches instead of going upstream. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Request for re-reviewAll four items are addressed — one of them by disagreeing with you, with reasons Two of those commits are filename corrections rather than prose. Your four
git -C $CORE grep -n 'validate-luhn' origin/master -- webapp/src/js/enketo/medic-xpath-extensions.js
# 226: 'cht:validate-luhn': luhn,Worth flagging that this one is not confined to the PR:
Neither the enum value nor the One correction while doing it: the premise does not hold uniformly.
git -C $CORE grep -n 'renderForm\|saveForm\|formService\.' origin/master \
-- webapp/src/ts/components/training-cards-form/training-cards-form.component.ts
# 124: private async renderForm(formConfig: FormConfig) {
# 130: this.form = await this.formService.render(formContext);
# 188: async saveForm() {
git -C $CORE grep -c 'FormService' origin/master -- webapp/src/ts/services/training-cards.service.ts
# (no match)So the grading tracks a real distinction rather than an inconsistency: this PR
Round-1 items, re-verified rather than assumed
What the gate found that the review did notThe bulk of the 19 commits. Grouped by class, since the individual items are in
The attribution sweep, run over this batchYour closing note on #123 asked for every "this PR added X" and "on master Y" 63 candidates, no real defects. 53 from the file-status screen, 10 from the
The one that needed real checking was On convergence, and why this round existsThe previous stopping point was not converged, and the pattern is worth naming Seventeen more findings came out of that, across six further commits. Rather than The three that were outstanding at the start of this round are fixed in it:
Gate
The counts matter less than the sequence. Across this branch the gate has run That bar exists because of how this corpus actually behaved. Coherence produced One operational note that cost real time: Disclosed rather than fixed: 27 Merging: behind
|
…ontacts)
Every item was checked against the PR's own diff and cht-core master before
being changed, not taken on the review's word. All four held up.
**9281 -- the getAll AsyncGenerator was inverted.** The draft said the generator
yields pages and showed a nested loop. It yields individual docs:
git -C $CORE show refs/verify/pr9281:shared-libs/cht-datasource/src/libs/data-context.ts
# getDocumentStream ... : AsyncGenerator<T, void>
# for (const doc of docs.data) { yield doc; }
git -C $CORE show refs/verify/pr9281:.../test/libs/data-context.spec.ts
# 131: it('yields document one by one'
Rewritten to the flat `for await (const person of Person.v1.getAll(ctx)(q))`
shape. Two facts found while verifying and now recorded: the PR squash-merged
into the `9193-api-endpoints-for-getting-contacts-by-type` feature branch
(`bf8a77da`, not an ancestor of master) and reached master only via #9311
(`34dd0303c`); and the helper was renamed before landing -- at #9311's squash it
is already `getPagedGenerator` in `libs/core.ts`, with `getDocumentStream` absent
and the signature already `AsyncGenerator<Person, null>`. Time-scoped, not
silently corrected to master's shape. The same PR also swapped getPage's numeric
`skip` for a string `cursor` and moved it ahead of `limit`
(`- return fn(personType, limit, skip)` / `+ return fn(personType, cursor, limit)`).
**10043 / 10057 / 9266 / 9281 / 9835 -- data-access, deferred with disclosure.**
The reviewer's own "extend vs use" rule is satisfied: all four anchor PRs touch
`shared-libs/cht-datasource` and nothing else (`git diff-tree --name-only` per
squash). Deferred per the reviewer's own sequencing on #122 -- "one coordinated
schema/taxonomy PR ... Not blocking any single PR" -- and the #123 precedent.
`data-access` is not a valid `domain` today (`agent-memory/schema.json` CHTDomain
enum holds 9 values, none of them it) and PR #152 adds it, open and unmerged, so
re-keying here would race #152 for the same enum value. Each of the five now says
so in its own text rather than leaving the reader to infer it.
**9007 -- Domain Rationale leakage stripped.** "Per the infrastructure pitfall"
is classifier scaffolding; replaced with the substantive reason. While verifying,
the vague `page_size` prose was pinned to the real constant:
`- private readonly PAGE_SIZE = 50;` / `+ private readonly PAGE_SIZE = 25;`.
Also dropped "verified with a manual quick test" -- PR #9007's body has an
entirely unchecked review checklist and says nothing about manual testing.
**9915 -- the dropped attribution, justified rather than restored.** Round 2
reworded "Reviewer verified the correct workflow (xlsx edit -> xml regeneration)
was followed" to drop "Reviewer". Restoring it would re-assert something the diff
contradicts: of PR #9924's 29 changed `.xml` files only 17 have a same-named
`.xlsx` beside them; the other 12 are the place create/edit forms, expanded from
4 shared `PLACE_TYPE-*.xlsx` templates and edited directly. The section now
states what is checkable from the diff. Counts corrected against the real file
list (50 files, all M -- 29 xml / 21 xlsx; default/app 10->11, covid-19/contact
6->8).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
sugat009
left a comment
There was a problem hiding this comment.
Round 3. All four of my round-2 items are resolved, and two of the resolutions are better than what I asked for: the 9592 keep-strong justification survives full verification (the component really owns the Enketo render/save lifecycle at the anchor, the #9840 rename is real, and neither weak sibling touches form-engine code), and the data-access deferral notes are factually right and mutually consistent. The 8656 and 8740 renames are legitimate title corrections.
Requesting changes on seven items below. Every one was verified with the same protocol: quote at head, check at the draft's own anchor, check on current master, and walk every commit that touched the region in between, so each comment states whether the defect is anchor-level or drift, and includes a suggested rewording. Five are blocking under the accuracy bar (a wrong sign, a wrong mechanism, a wrong attribution, a false read/write claim, and a duplicate identity), two are wording.
One systemic suggestion: standardize a template for epic-branch work, "merged into on ; not on master". The corpus currently errs in both directions (10767 treated an epic-branch merge as shipped; 10922 here calls merged PRs unmerged), and one sentence pattern fixes the class.
| ## Solution | ||
|
|
||
| Updated the form loading code in `generate-xform.js` to not request attachments in the `_all_docs` call. Instead, attachments are loaded separately per form, and only the relevant ones (XForm XML) are fetched. PR #10248 changed 5 files in the API layer. | ||
| Dropped `attachments` from both reads: `forms.js`'s `_all_docs` call now passes only `include_docs`, and `generate-xform.js`'s `update` now calls plain `db.medic.get(docId)`. Attachments are then loaded separately, by name, per form. Only one attachment is read: the XForm XML, whose name is resolved dynamically by the new `formsService.getXFormAttachmentName(doc)` helper (literally `xml`, or any `*.xml` other than `model.xml`). `model.xml` and `form.html` are not read at all — they are the generated outputs generate-xform.js writes back onto the doc (:243, :247). Large media attachments are never loaded during startup or form processing (PR #10248). PR #10248 changed 5 files in the API layer. |
There was a problem hiding this comment.
issue (blocking): "model.xml and form.html are not read at all" and "Only one attachment is read" are both false, and not rescueable by time-scoping. PR #10248 itself ADDED the reads: its own diff contains + formsService.getAttachment(doc._id, 'form.html') and + ... 'model.xml' inside updateAttachments, which fetches THREE attachments in one Promise.all (the XForm XML plus these two, as inputs to addGeneratedAttachments). Only two commits have touched generate-xform.js since (#10634 error logging, #10949 xsltproc hardening) and neither touches that region, so master's :254-261 is byte-for-byte what #10248 wrote. The true story is "named reads instead of bulk reads": #10248 stopped loading ALL attachments and switched to fetching exactly three by name. Suggest replacing the two quoted claims with that framing; the write-back description (:243, :247) is correct and stays.
|
|
||
| ## Problem | ||
|
|
||
| `npm run unit-webapp` failed for developers outside UTC-4: the `medic-xpath-extensions` mocha suite (`#difference-in-months` and every `#to-bikram-sambat()` case) baked the runner's local timezone into its expectations, so results came out off by a day or a month in e.g. NZ (+12) — tracked in #8556. This was a test-determinism problem, not a defect in the extension functions themselves; no deployed form behaviour was wrong. |
There was a problem hiding this comment.
issue (blocking): Date.prototype.getTimezoneOffset = () => -240 emulates UTC+4, not UTC-4, so "failed for developers outside UTC-4" (summary, line 10; Problem, line 47) is wrong on both sign and scope.
getTimezoneOffset() returns UTC minus local time in minutes, and the distilled commit's own spec proves the convention: at 7202de54, webapp/tests/mocha/unit/enketo/medic-xpath-extensions.spec.js lines 24-25 stub () => -60 and assert getTimezoneOffsetAsTime returns '+01:00', lines 29-30 stub () => 60 and assert '-01:00', so -240 is '+04:00'. Scope is also over-strong: the fix changed no to-bikram-sambat expectations, those same expectations passed pre-fix in CI at UTC, and issue #8556's failures were reported from NZ (+12). The suite was timezone-dependent, passing in some zones (UTC included) and failing in others, not "passing only at UTC-4".
Suggested rewording for both places: "the suite baked timezone-dependent expectations into its cases, so npm run unit-webapp failed in some timezones (e.g. NZ +12, per #8556) while passing in others such as UTC; the fix pins getTimezoneOffset to -240 (emulating UTC+4) so results are identical everywhere."
nitpick: "every #to-bikram-sambat() case" (line 47) is over-broad. At 7202de54 that describe holds 5 conversion cases plus 11 invalid-input cases asserting an empty string, which are timezone-independent; #8556's log shows exactly the 5 conversion cases failing. "Every #to-bikram-sambat() conversion case" would be accurate.
|
|
||
| ## Problem | ||
|
|
||
| The cht-datasource local data context could not create reports. Consumers operating against the local (direct-database/PouchDB) adapter could not create report documents through the datasource abstraction, leaving the local context behind the intended create capability. On the remote/API side the same gap existed: the report module exposed only read operations, with no remote create implementation, API controller method, or POST route for creating reports, even though person already had a full create path on the epic branch by the time this PR landed — `Person.v1.createPerson`, a `createPerson` handler in `api/src/controllers/person.js`, and a `postResource` call for the `api/v1/person` route in `shared-libs/cht-datasource/src/remote/person.ts` are all present at this PR's parent `cab214534`. Place had none yet; that half is tracked as #10038 (PR #10099). |
There was a problem hiding this comment.
issue (blocking): The draft contradicts itself about PR #10099, and the place-create attribution at lines 59 and 75 is wrong. Line 69 has it right: #10099 ("feat(#10040): add API support to create reports", merged 2025-07-03 as d19e4e507 on the epic branch, related issue #10040) only touched the person and place create paths to align validation. Its place.ts diff swaps assertPlaceInput for validatePlaceInput on already-standing create wiring, and its place.js diff adds can_create_places to the existing createPlace handler. But line 59 says the place half "is tracked as #10038 (PR #10099)" and line 75 says place.ts's create path "was not [standing], and was added alongside this work by the same #10099". Both are false. The place create path (#10038, "To have API that can create places") was added earlier on the epic branch by PR #10065 ("feat(#10038): implement createPlace local", 169a02355) and PR #10089 ("feat(#10038): add API support to create place", 98a687a80, merged 2025-06-26), with #10094 (806456120) converting the create surface to PlaceInput. By the time #10099 landed, both person and place create paths were standing. Note line 59's "Place had none yet" is true at this draft's anchor cab214534 (no create in place.ts, local/place.ts, or api/src/controllers/place.js there), so only the parenthetical needs fixing. Suggested edits: line 59, replace "(PR #10099)" with "(local PR #10065, API PR #10089)". Line 75, replace the clause after "mirroring person.ts" to say both the person and place create paths were already standing on the epic branch when #10099 landed (place via #10065 and #10089), and #10099 aligned their validation while adding the report path. Line 121 is accurate as written and needs no change.
|
|
||
| ## Testing | ||
|
|
||
| Updated the existing `tests/e2e/default/enketo/pregnancy-danger-sign-follow-up.wdio-spec.js` WebdriverIO spec for the new relevance/widget behaviour; that is the only test change the epic squash carries. Note that #8740 is an epic child merged into the `7599-uplift-enketo-7` branch and squashed as #8528 (`314e79061a`), so its own commit sha is no longer resolvable in a clone — verify file claims against the squash, not `source_sha`. |
There was a problem hiding this comment.
suggestion (non-blocking): The "only test change the epic squash carries" half checks out, but the characterization does not. Squash 314e79061a's entire test diff is +2/-2 in tests/e2e/default/enketo/pregnancy-danger-sign-follow-up.wdio-spec.js, and both lines only change excludingEvery('instanceID') to excludingEvery(['instanceID', 'deprecatedID']) in the edit-report assertions, needed because enketo-core v7 populates meta/deprecatedID on edited submissions. That is edit-metadata fallout of the uplift, not relevance/widget coverage. PR 8740's actual widget-behavior test edits, removing the browser.keys('Escape') datepicker workaround in tests/e2e/cht-form/default/death-report.wdio-spec.js and tests/page-objects/default/enketo/delivery.wdio.page.js, netted to zero in the squash (the workaround is absent from 314e79061a^), so they are invisible there. Suggest rewording to: "The epic squash's only test change is tests/e2e/default/enketo/pregnancy-danger-sign-follow-up.wdio-spec.js, which adds 'deprecatedID' to two excludingEvery() exclusion lists because enketo-core v7 sets meta/deprecatedID on edited submissions. PR 8740's own widget-behavior test edits (Escape-workaround removals in death-report.wdio-spec.js and delivery.wdio.page.js) cancelled out within the epic branch and do not appear in the squash."
|
|
||
| ## Problem | ||
|
|
||
| > **Not on `master` (as of 2026-08-09).** Neither PR #10922 nor PR #11116 has been merged. The commits live only on the epic branches `origin/10700-photo-capture`, `origin/10700-photo-capture-in-sub-contacts-and-reports` and `origin/5.1.2-FR-attachments-for-subcontacts`; none of them is an ancestor of `origin/master`, and neither `resolveOwnerDoc` nor `findFileNodeByFilename` exists in `webapp/src/ts/services/enketo.service.ts` on `master`. Everything below describes the state of those branches, not shipped behaviour. (The frontmatter `source_sha` `cc34e08664…` and the current branch head `0df57c664…` are two rebased copies of the same squash.) |
There was a problem hiding this comment.
issue (non-blocking): The banner's core scoping is verified correct: neither cc34e08664 nor 0df57c664 is an ancestor of origin/master (checked at 6eb2ac0f1), resolveOwnerDoc/findFileNodeByFilename appear nowhere on master (and never have, git log -S is empty), and the two shas really are rebased copies of the same #10922 squash (identical git patch-id --stable 530a4a2a1137, same author, date, and subject). Three details are wrong, though:
- "Neither PR #10922 nor PR #11116 has been merged" is false. Both are merged=true on GitHub: #10922 merged 2026-05-19 into
10700-photo-capture-in-sub-contacts-and-reports(its squash merge commit is exactly the frontmattersource_shacc34e08664), and #11116 merged 2026-05-29 into5.1.2-FR-attachments-for-subcontacts(squashe88c88361). Reword to "merged only into the epic branches, not intomaster", and update the frontmatter summary's "NOT YET MERGED" and the "unmerged epic branch work" concept to match. - "the current branch head
0df57c664" is inaccurate. No ref points at that sha; it is an interior commit oforigin/10700-photo-capture, whose head has beenbade9485bsince 2026-07-10, before this banner's "as of 2026-08-09" stamp. The sha that IS a current branch head iscc34e08664itself (tip oforigin/10700-photo-capture-in-sub-contacts-and-reports). Suggest: "thesource_shacc34e08664(head oforigin/10700-photo-capture-in-sub-contacts-and-reports) and0df57c664(a rebased copy onorigin/10700-photo-capture) are the same squash". - "The commits live only on the epic branches [all three]" overstates. Neither sha is contained in
origin/5.1.2-FR-attachments-for-subcontacts; that branch carries the equivalentenketo.service.tschanges via the #11116 squashe88c88361instead.
|
|
||
| ## Design Choices | ||
|
|
||
| Pushed the index-shape decision down into cht-datasource so future changes to the freetext indexes are invisible to the validation lib — the stated goal of #9653. Callers therefore no longer choose a view or a key range: cht-datasource decides internally whether a qualifier hits the keyed offline view, a range scan, or Nouveau, based on whether the freetext contains a `:` separator. Delegating rather than rewriting the validators kept backwards compatibility with existing data and configuration. |
There was a problem hiding this comment.
issue (blocking): The ':' separator does not route between Nouveau and the offline path, so this sentence misattributes the routing. On current master, getUuidsPage (shared-libs/cht-datasource/src/local/report.ts) chooses Nouveau vs offline views via useNouveauIndexes(medicDb) (src/local/libs/nouveau.ts), which returns true when the _design/medic-offline-freetext ddoc is absent, i.e. when running server side. The ':' check (isKeyedFreetextQualifier, src/qualifier.ts) only selects keyed exact-match vs prefix range scan inside the offline view path, plus exact_match vs fuzzy syntax inside the Nouveau query. At this draft's anchor (e4d7bdc8, the #9755 merge), Nouveau was not in this code path at all: getUuidsPage queried medic-client/reports_by_freetext, with ':' selecting keyed vs range (Nouveau replaced the views later, in f1bdfc07c, feat(#9542), PR #10201). Suggested rewrite of the second sentence: "Callers therefore no longer choose a view or a key range: cht-datasource decides internally which index a qualifier hits. It uses Nouveau when running server side (no medic-offline-freetext ddoc in the db) and the offline reports_by_freetext view otherwise, doing a keyed lookup when the freetext contains a ':' separator and a prefix range scan when it does not." For the record on the round-2 item: the whitespace-fallback claim was fully removed from all six sections in b82840f, and no residue remains at head; the remaining defect is this replacement sentence, which that same commit introduced.
| category: feature | ||
| domain: forms-and-reports | ||
| domainFit: strong | ||
| issueNumber: 8074 |
There was a problem hiding this comment.
issue (blocking): this draft duplicates the identity of a landed contacts draft. Lines 2 and 6 carry id: cht-core-8074 / issueNumber: 8074, which agent-memory/domains/contacts/issues/8074-filter-contact-search-by-parent.md has owned on main since #79 (a0108f7) and which #132 is actively correcting (55dbd0a, 1973657). The key itself is right, cht-core PR 8759's closingIssuesReferences is exactly #8074, and 25e7558 deterministically re-keyed this file from cht-core-8759 to cht-core-8074. But that relink made it a second memory for one issue: the two files share the identical 7-file Related Files set and describe the same change, and they have already diverged once (the set-intersection description was fixed only on the contacts side in 55dbd0a). The 849aa01 collapse pass enforced "one memory per issue" and "no duplicate issueNumbers" within forms-and-reports only, so this cross-domain pair slipped through, the same blind spot 55dbd0a documented for the 8034/data-sync pair.
Suggestion: remove this file from #122 and fold its unique content into the contacts canonical (the specific unit/e2e spec paths in Testing, and the with-same-parent to descendant-of-current-contact naming rationale in Design Choices), mirroring how 849aa01 moved the #9835 pair to "the contacts canonical that owns the issue". Do not re-key it back to 8759; that is a PR, not an issue, which is exactly what 25e7558 fixed, and PR 8759 closes no other issue it could be keyed to. If the team instead decides forms-and-reports should own this memory, that is a relocation of the single canonical draft (a corpus decision touching a landed file), never a second copy. Given this is the second cross-domain duplicate to escape the per-domain gate, a corpus-wide issueNumber uniqueness check in validate-schema would close the class.
Promotes 47 strong-fit
forms-and-reportsdrafts fromagent-memory/_pending/intoagent-memory/domains/forms-and-reports/issues/for squad content review.Categories: feature (21), bug (20), improvement (6)
Themes: Enketo widgets & XPath extensions, cht-datasource report create/update, SMS parser, form validation/submission hardening.
All 47 carry
domainFit: strong+ a## Domain Rationalesection. 5 weak-fit drafts deferred for later.seeding-claude-cli-v2(feat(#108): seeding pipeline - CLI provider, domain-rationale, infrastructure domain, concurrency #119) — retarget tomainafter the schema lands.validate-schema: passing, 0 failures.