Taaktypes (werkregels en opgeslagen werk): ontwerp + bouwstappen 1–7 — gestapeld op de XER-branch - #101
Open
Nozzit wants to merge 171 commits into
Open
Taaktypes (werkregels en opgeslagen werk): ontwerp + bouwstappen 1–7 — gestapeld op de XER-branch#101Nozzit wants to merge 171 commits into
Nozzit wants to merge 171 commits into
Conversation
…pt na drie verkenningsrondes)
…ariteit/uurmodus als kernbesluit, SCHEDOPTIONS-defaults-programma, whitelist-invoerregel, projectselectie herzien, X-O5 getalnotatie, mutatiebewijzen per taak
…ti-project-import, baselines verplicht bewaard, float-vangrails bekrachtigd
…ijk (Hotel-paar via schema-vingerafdruk), X-O1/X-O2 doorvertaald (X4a/X4b-knip, per-project-meting, lege-projectregel, baseline-begrenzing), defaults op de meting, generieke enum-regel
…e-eis op drie plekken (docblok, 14-talige foutmelding, gidsparagraaf)
…ECT-rij terug in X4a, enum-regel gesplitst naar §4.7, X4b→X10-pijl, stale zinnen gelijkgetrokken
XER-etappe, taak X0 (SERIEEL VOORAF). Geen lezer, geen registry-entry — alleen typecontract + corpustooling, conform de X0-brief en plan §4.1/§6. - src/types/task.ts: P6DurationType/P6ActivityType + Task.p6DurationType/ p6ActivityType/p6SuspendResume (veld-als-signaal naast mspTaskType, met de vastgelegde superset-afspraak voor de latere taaktypes-etappe; suspend/ resume-herkomstvlag is een stub, X7 vult hem). - Doorgevoerd op alle compile-gedekte plekken die anders stil hadden kunnen verouderen: extTypes.ts/extMappers.ts (Ext-contract, leeskant-alleen zoals mspTaskType/effortDriven), check-ext-contract.ts (sleutellijsten), moveProject.ts (TASK_VERDICTS, 'n/a'), check-ifc-roundtrip.ts (Required<Task>- getuige + TASK_CANON skip-cellen, IFC-wiring is X9), taskFields.ts (REJECT_HINTS, MCP-zetbaarheid). - tests/planning/check-xer-field-whitelist.ts: de drie §4.1-bakken (whitelist/ verboden/genegeerd) als getypeerde constanten + een eigen, onafhankelijke %T/%F-corpusscan (OPS_XER_CORPUS) die de union van alle TASK-kolommen tegen de bakken toetst — het gatenkaas-mechanisme. Skip-OK zonder corpus, geen CI-poort (zelfde conventie als OPS_MPP_CORPUS). - tests/planning/xerFidelityTypes.ts + xer-fidelity-baseline.json + check-xer-fidelity-baseline-schema.ts: het harness-skelet — de §3-baselinevorm (zes assen, deviations/measurable) vastgelegd via een compile-locked sleutellijst + runtime-structuurvalidator, met een lege-lezer-run (createEmptyXerFidelityBaseline) die de committe lege baseline produceert. De dedup-logica zelf (§2) is X1-werk. - run.sh: beide nieuwe checks bedraad naast check-mpp-fidelity. Mutatiebewijzen (uitgevoerd, teruggedraaid): whitelist-veld schrappen ⇒ corpusscan ROOD; baseline-vorm muteren (JSON) ⇒ schema-check ROOD; veld uit XerFidelityBaselineEntry schrappen ⇒ compile-fout. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Her-review 2 (P2) liet zien dat een pagineersessie stil records van het verkeerde project combineert: page 1 opvragen op document A, met switchDocument naar document B wisselen, en page 2 levert dan gewoon een (mogelijk lege) pagina van B terug zonder enige waarschuwing — een extensie die een lege pagina als "klaar" leest heeft in werkelijkheid twee projecten door elkaar gehaald. Er was geen driftanker zoals het bestaande expectedDocId in de MCP-laag. getImportSourceCatalogPage(collection, options) accepteert nu een optionele options.expectedSourceProjectId. Wijkt de bronselector van het ACTIEVE document af — ook als dat document inmiddels helemaal geen XER-bron meer heeft — dan gooit de aanroep een nieuwe ExtImportSourceDriftError in plaats van stil door te gaan. De check zit zowel in de pure getExtImportSourceCatalogPage (archief aanwezig, ander project) als in de extensionApi-wrapper (archief helemaal weg na een documentwissel), want de tweede route riep de eerste anders nooit aan. Meegenomen kleine P3-fixes uit dezelfde her-review: offset -0 canoniseert nu naar +0 (resolvePageOffset), en docs/extensions.md + docs/wiki/Extensions-Authoring.md noemen nu expliciet dat deze bronroute apiVersion >= 1.1 vergt. Mutatiebewijs: de assertNoImportSourceDrift-aanroep weghalen uit zowel getExtImportSourceCatalogPage als de extensionApi-wrapper laat de nieuwe D1/D2-checks in check-ext-contract.ts rood lopen (256 → 2 rood: "kreeg isDriftError:false" i.p.v. de verwachte fout), exit 1; D1a/D3 (het bestaande, ongewijzigde gedrag zonder de optie) blijven daarbij groen. (cherry picked from commit 0816d57)
…flake)
check-milestone-duration-render.ts liet project.startDate en view.viewStartDate
allebei op de "vandaag"-default staan. Op zaterdag/zondag schoof de solver de
basistaak naar de eerstvolgende werkdag terwijl het view-origin op het
weekend bleef staan — de balk verschoof pixels naar rechts, terwijl de
hittest een vaste x = TTW + 20 gebruikt. Anker nu beide op dezelfde vaste,
altijd-werkende maandag (2026-01-05, in de stijl van check-bar-colors.ts),
zodat de fixture niet meer van de kalenderdag van de testrun afhangt.
Mutatiebewijs: met een gefakete Date ("vandaag" = za 2026-01-10) faalt de
ONGEWIJZIGDE check exact zoals gerapporteerd (getTaskBarBounds → null); met
de fix erin blijft hij groen onder diezelfde gefakete zaterdag én onder de
echte datum van vandaag.
(cherry picked from commit a133ae6)
(cherry picked from commit 38060ed)
Reviewbevindingen uit review-mcp-read.md (P1, twee stuks): - planner_inspect_xer_provenance stond op batchable:true. Een planner_batch met alleen deze tool liep zo via de mutatie-executor: altijd een transactie, altijd runCPM/recomputeViewRows/recomputeResourceLoad — in strijd met de eigen "voert geen CPM uit"-belofte. Nu batchable:false, zodat checkExclusions (batchTool.ts) de stap al vóór enige transactie met VALIDATION afwijst. - resourceCatalog/metadataCatalog/taskSourceRowsByProject gaven ruwe XER-cellen (namen, notities, willekeurige kolommen) zonder enige opt-in en zonder limiet per cel/rij/respons terug. Nieuw: `includeRawRows` (alleen geldig bij die drie sections). Zonder opt-in levert elke rij alleen `line`+`fieldCount`, geen cellen. Met opt-in: per-cel afkapping op 2.000 tekens, een verlaagde paginalimiet (100 i.p.v. 1000, zoals rawSource al deed met 8 chunks) en een responsgrens van 256 kB die met een pagineerhint faalt. Tests in cases-xer-provenance.ts uitgebreid: batch-uitsluiting (geldige én ongeldige args), default-projectie zonder cellen, afkapping bij opt-in, en een losse responsgrens-fixture (100 rijen × 3 grote cellen) die de 256 kB-grens bewust raakt. Alle vier nieuwe gedragingen zijn mutatiebewezen (fix uit ⇒ check rood): batchable terug naar true, projectSourceRow zonder gating, en finalizeBounded weggehaald gaven elk de verwachte faalregel. (cherry picked from commit 4ab7c9e)
Reviewbevinding P2 (review-mcp-read.md #3): een ongeldige batch-stap gaf terecht VALIDATION, maar de review zag isDirty toch naar true kantelen omdat restoreSnapshot() (snapshot.ts) — voor de gewone undo/redo-tegenhanger — die vlag altijd op true zet. Op de huidige basis (na de store-contextrefactor) is dit al opgelost: createMcpTransactions.ts's run() herstelt op het rollbackpad expliciet `state.isDirty = previousDirty` NA restoreSnapshot. Dit is dus een algemene batcheigenschap, geen zaak van de XER-tool zelf — de nieuwe test pint 'm met een stub-tool met een strikt schema (additionalProperties:false + required), zodat een toekomstige regressie in die rollback-volgorde hier meteen rood wordt. Mutatiebewezen: de previousDirty-restore-regel tijdelijk verwijderd uit createMcpTransactions.ts liet precies deze test falen (isDirty false → true). (cherry picked from commit 21c4509)
Herbeoordeling (review2-3d.md) op de vorige fix: die dichtte precies de drie
paden die het eerste rapport noemde, maar de EIGENSCHAP ("elke string uit een
bronrij gaat door één afkap-/opt-in-poort") stond nog los. Twee gaten eronder:
- [P1 #1] `diagnostics/documentViews` had géén `includeRawRows`-gating, géén
projectie en géén responsgrens — `resources.assignments[].rawRow` gaf ruwe
XER-cellen (bevestigd met een ECHTE `readXER`-fixture, geen stub: 50.000
tekens vrije tekst kwam onafgekapt terug).
- [P1 #2] De gate hing aan `rawRow.cells`; vrije tekst BUITEN `rawRow`
(`taskProjections.notes`, `roleSources.description`, `customFields`-waarden)
ging ongefilterd mee, ook al heetten de collecties "genormaliseerd".
Fix: één generieke poort (`sanitizeProvenanceValue`) die recursief over een
sectierespons loopt. Een `{line,cells}`-vorm wordt STRUCTUREEL herkend
(werkt dus ook op plekken zonder eigen allowlist-regel, zoals geneste
documentViews-assignments). Een string onder een vrije-tekstsleutel
(`notes`/`description`/`customFields`) is zonder `includeRawRows` volledig
onzichtbaar, met opt-in afgekapt op 2.000 tekens. Elke andere string (namen,
labels, ids) blijft altijd zichtbaar maar hard afgekapt op 200 tekens — nooit
meer "genormaliseerd" gelijk aan "onbegrensd".
Twee kleinere P2/P3-bevindingen uit dezelfde ronde in dezelfde beweging
meegenomen:
- [P2 #3/#6] `finalizeBounded` nu ook om `diagnostics`/`importReport`; een
`ByteBudget` charged tijdens de projectie en breekt af zodra het budget vol
is (vóór de dure volledige serialisatie), plus een harde cap van 200
cellen/velden per rij (de `%F`-kolomkop van het bronbestand bepaalde dat
aantal voorheen ongebonden).
- [P2 #4] de responsgrens meet nu ECHTE UTF-8-bytes (`TextEncoder`) i.p.v.
`String.length` (UTF-16-code-units) — voor CJK/Arabisch/emoji zat daar een
factor 2–3 tussen.
- [P2 #5] `projectIds()` is nu de unie van `documentViews` en
`taskSourceRowsByProject`: een project dat alleen TASK-rijen heeft (leeg of
baseline-uitgesloten) werd door `summary` geadverteerd maar door de tool
zelf met NOT_FOUND geweigerd.
- [P3 #7] `truncateAt` knipt nooit meer een surrogaatpaar door de helft.
- [P3 #8] een nieuwe test loopt via de ECHTE dispatch-weg (`handleMcpMessage`)
i.p.v. uitsluitend `def.handler`.
Alle nieuwe/aangepaste tests in `tests/mcp/cases-xer-provenance.ts` zijn
mutatiebewezen (fix uit ⇒ exact de bijbehorende test rood): structurele
rawRow-detectie uit ⇒ 7 tests rood; vrije-tekstsleutels leeg ⇒ 2 tests rood;
cap+budget+finalizeBounded alledrie uit ⇒ 3 tests rood (los uitgezet blijven
de andere twee lagen het nog opvangen — bewuste defense-in-depth); bytes
terug naar code-units ⇒ 1 test rood; selectorbron terug naar alleen
documentViews ⇒ 2 tests rood.
(cherry picked from commit c3c8487)
…ixes
Her-check (review2-3d.md, ronde 3) op de vorige commit: de generieke rijdetectie
werkte, maar de vrije-tekstclassificatie was zelf nog een BLOCKLIST
(`notes`/`note`/`description`) — dezelfde soort blinde vlek als de drie-paden-
fout van ronde 1, alleen een niveau dieper. Vijf bevindingen, alle bevestigd
met probes door de reviewer:
- [P1 N1/N2] Blocklist omgekeerd naar DENY-BY-DEFAULT: `SAFE_LABEL_KEYS` is nu
een allowlist van id-/code-/labelachtige sleutels die zonder opt-in zichtbaar
blijven (afgekapt op 200 tekens). Alles wat er niet in staat — ook een
onbekende toekomstige sleutel — is zonder `includeRawRows` volledig
onzichtbaar. Dit dekt automatisch ook geneste vrije tekst: `Task['notes']`
is een objectarray (`{id,text,done}[]`), geen string, en de oude blocklist
keek alleen naar de buitenste sleutel `notes`, niet naar `text` binnenin.
Zes alias-sleutels (`text`/`comment`/`memo`/`remark`/`title`/`longName`) die
vorige ronde allemaal doorglipten, verdwijnen nu net als elke andere
niet-toegestane sleutel — geen aparte regel per synoniem nodig.
- [P2 N3] `summary` (de DEFAULT-sectie) liep door geen van beide poorten:
911.534 bytes gemeten, `numberFormat.currencyCode` onafgekapt (5.014
tekens), en `importReport` was een levende alias naar het bevroren archief
— het kopcommentaar belooft expliciet "nooit een alias". `summary` loopt nu
door dezelfde `sanitizeProvenanceValue` + `finalizeBounded` (met
`includeRawRows` hard op `false`, want summary zat nooit in
`RAW_ROWS_SECTIONS`).
- [P2 N4] Cel-/veldNAMEN (de `%F`-kolomkop van het bronbestand) ontsnapten aan
zowel afkapping als budget — een kolomnaam van 60.001 tekens kwam verbatim
mee en telde als nul in de teller. Nu lopen sleutels door dezelfde
`truncateLabel` + `budget.charge` als waarden, met botsingsveilige
suffixering (`#1`, `#2`, …) na afkapping.
- [P2 N5] `isRawSourceRowLike` eiste exact twee sleutels en faalde daardoor
OPEN zodra een rijvorm een derde veld droeg (`XerScheduleOptionsSourceRow`
= `{table,line,cells}`): zo'n rij viel door naar de generieke objecttak,
waar `cells` gewoon een record werd en elke celwaarde als zichtbaar label
naar buiten kwam. Detectie is nu op VORM (`line`+string-`cells`), fail-
closed; overige velden (`table`) projecteren gewoon mee via dezelfde poort.
- [P3 M4] Het `ByteBudget`-effect (begroten vóór serialisatie) was door geen
enkele test gepind: de reviewer schakelde alleen de budgetdrempel uit en
geen enkele test werd rood, omdat `finalizeBounded` dezelfde oversized
respons toch nog post-hoc afving. Nieuwe test pint het VIA de foutmelding:
`createByteBudget` mist het woord "geserialiseerd" dat `finalizeBounded`
wél toevoegt, dus een assertie op die tekst onderscheidt "geweigerd tijdens
projectie" van "geweigerd na volledige serialisatie" — zonder op tijd of
geheugen te meten.
Tool-description bijgewerkt naar wat de code nu daadwerkelijk garandeert
(deny-by-default, summary inbegrepen, cel-/veldnamen afgekapt).
Alle vijf fixes zijn mutatiebewezen (fix uit ⇒ exact de bijbehorende
test(s) rood): allowlist naar "alles toegestaan" ⇒ 2 tests rood; summary
buiten de poort ⇒ 2 tests rood; kolomnaam-afkapping uit ⇒ 1 test rood;
kolomnaam-begroting uit (afkapping blijft aan) ⇒ 1 test rood; rijdetectie
terug naar exact-2-sleutels ⇒ 1 test rood; ByteBudget-drempel uit ⇒ zowel de
nieuwe M4-pinningtest als de N4-budgettest rood (bevestigt exact het gat dat
de review aanwees: de oude suite zag deze mutatie niet).
(cherry picked from commit 7bc7130)
…ak door poort Her-check 3 (review2-3d.md): GO onder twee kleine voorwaarden. - [P2 R8] De generieke objecttak van sanitizeProvenanceValue deed `out[childKey] = …` met `childKey` ongemoeid — N4 dichtte dit alleen voor projectSourceRow/projectFreeTextMap. Een project-id van 80.000 tekens (proj_id komt uit het bronbestand) overleefde daardoor verbatim zodra hij als OBJECTSLEUTEL werd gebruikt (summary.catalogCounts.taskSourceRowsByProject), terwijl dezelfde string als WAARDE (selector.availableProjectIds) al wél afgekapt werd. Nu lopen sleutels door dezelfde truncateLabel + budget.charge als waarden, met dezelfde botsingsveilige #N-suffixering. - [P3 R9] De sourcePresent:false-tak van summary retournede vóór sanitize/ finalizeBounded, met het commentaar "statische, systeemeigen tekst" — maar xerSourceProjectId is een documentveld uit het bestand, geen statische tekst. Nu loopt ook deze tak door de poort; alleen de echt statische systeemmelding (note) wordt na het saneren teruggezet, want die sleutel staat bewust niet op de allowlist. - [P3 R7, optioneel] Een volledig verborgen string-array werd `[null, null]` in plaats van iets dat "hier is iets verborgen" communiceert — de array-tak filtert nu undefined-elementen eruit. Allowlist-docblok aangevuld: `name`/`code` blijven zichtbaar vastgelegd als geaccepteerd risico (een P6-resourcenaam is vaak een persoonsnaam — geen AVG-schone lijst), `unit`/`currShortName` verwijderd (kwamen nergens in de blootgestelde grafiek voor), `unitOfMeasure` gemotiveerd als wél live. Mutatiebewezen: R8 teruggedraaid ⇒ de nieuwe R8-test rood (sleutel weer 80.000 tekens); R9 teruggedraaid ⇒ de nieuwe R9-test rood (currentProjectId weer 9.009 tekens in plaats van 200). (cherry picked from commit 63e068c)
… (7b-1/7b-2)
Etappe 7b-1 en 7b-2 landen bewust SAMEN: elk afzonderlijk maakt het corpus
meetbaar slechter (zie de meting onderaan).
OORZAAK (7b-1). De `Exceptions`-lijst van kalender 842 (`R111 - 1`) in
`crawl-xer-extra/jailaff-xer-splitter/rehab-2.xer` slaat aaneengesloten vrije
blokken op met een klem op de MA-VR-as: elke zaterdag staat er als de vrijdag
ervóór, elke zondag als de maandag erná. Blok 2008-09-29 … 2008-10-09 staat er
letterlijk als `39720 39721 39722 39723 39724 39724 39727 39727 39728 39729
39730` — 10-04 (za) en 10-05 (zo) ontbreken, 10-03 (vr) en 10-06 (ma) staan er
twee keer. Zo'n AANGRENZEND DUPLICAAT is het bewijs dat er een dag verloren
ging, en komt in het hele corpus van 93 bestanden in geen enkel ander bestand
voor. Alle 23 redundante records van die kalender staan op een vrijdag of een
maandag (nul op een andere weekdag), en de tien dagen die de set-cover van het
761-diagnosedossier onafhankelijk als "moeten vrij zijn" aanwees (2008-10-04,
10-05, 2008-12-07, 12-13, 12-14, 2009-09-19, 09-20, 2009-11-28, 11-29,
2009-12-05) zijn exact de klemdoelen van tien van die 23 records — één-op-één,
geen rest.
OORZAAK (7b-2). Voor precies diezelfde records maakte de decoder een
`p6NonWorkPenaltyDate`: een virtuele extra niet-werkdag die
`CalendarEngine.subtractP6XerProjectedWorkMinutes` bij elke achterwaartse
duur-/lagwandeling opnieuw meetelt. Reconstrueren we de dag écht, dan zou
dezelfde afwezigheid twee keer verrekend worden. Gemeten op rehab-2 met de
blokken vrij: `addWorkMinutes(2009-11-25T08:00, 56u)` = 2009-12-12T17:00 en
`subtractWorkMinutes` daarvan = 2009-11-25T08:00 (beide exact P6's LF/LS),
terwijl de projectie 2009-11-22T08:00 gaf — drie werkdagen te vroeg, exact de
drie penaltydagen 2009-11-27, 11-30 en 12-04 in dat venster.
WIJZIGING. `xerCalendarData.ts` reconstrueert de geklemde weekenddag
(`weekendClampTarget`) en laat voor die datum géén penaltydatum meer achter. De
poort is drievoudig: de kalender moet zelf een aangrenzend duplicaat dragen, het
klemdoel moet een zaterdag of zondag zijn die op déze kalender WERKT, en die dag
mag niet al een eigen uitzonderingsrecord hebben. Corpusmeting van die poort:
92 van de 93 bestanden zijn byte-identiek; alleen rehab-2 verandert. De
projectie zelf blijft staan — een generieke "sla een al vrije dag over"-wacht
zou haar de facto schrappen en dat is gemeten slechter (zie hieronder); ze is
voor twaalf andere corpusbestanden nog steeds het enige model.
METING — X12-productfidelity (`OPS_XER_FIDELITY_REPORT`, per bestand):
totaal 18398 → 17421 (−977)
rehab-2.xer 14812 → 13835 (−977)
alle 28 overige bestanden ongewijzigd, 0 verschil
per as: es 1251 → 1573 (+322) ef 1500 → 1627 (+127)
ls 5015 → 4546 (−469) lf 5044 → 4583 (−461)
tf 4765 → 4468 (−297) ff 823 → 624 (−199)
De twee helften afzonderlijk (mutatiebewijs op corpusniveau):
alleen reconstructie, penalty blijft 18398 → 21673
alleen penalty weg, geen reconstructie 18398 → 21588
beide samen 18398 → 17421
Corpusloos mutatiebewijs: `check-xer-calendar-data.ts` sectie 22 draait de
letterlijke recordreeks van blok 2009-11-26 … 2009-12-05 en eist tien
aaneengesloten vrije dagen plus een lege penaltylijst; zonder deze fix zeven
dagen en drie penaltydatums (exit 1). Twee controles erbij: zonder duplicaat
gebeurt er niets, en op een gewone ma-vr-kalender ook niet.
Poorten: `OPS_XER_CORPUS=… npm run test:planning` exit 1 met uitsluitend de
toegestane rode set — de vier X12-regels (totaal nu 17421 i.p.v. 18398) — plus
`milestone-duration-render`, dat op de basiscommit a669108 al rood staat en
niets met deze etappe te maken heeft. `npm run typecheck` exit 0,
`npm run lint` exit 0. Drie gepinde baselines meebewogen en opnieuw gemeten:
de 124-kalenderdigest, de SCHEDOPTIONS-blast-radius (expectedFinishVariant en
causalProductEffects) en de openbare task-replaypin.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit fbcdb73)
…erkt na review)
Herwerking van `fbcdb731` na de hyperkritische review (`review-7b.md`, NIET LANDEN).
Alle zeven punten afgewerkt, elk met eigen meting.
1. POORT PER RECORD (was: per kalender). `adjacentDuplicateDates.size > 0` schakelde
de hele kalender om; de reviewer bewees daarmee twee false positives. De poort zit
nu op het record zelf, in twee benoemde bewijsvormen (`hasWeekendClampEvidence`):
* SPRONG — het record staat op een vrijdag én er is een uitzondering op de maandag
erná (of andersom), met een werkend, niet-opgeslagen weekend ertussen;
* DUPLICAAT MÉT BLOKVERVOLG — aangrenzend duplicaat én het blok loopt aan de
binnenzijde door.
Fidelity ongewijzigd: rehab-2 blijft 13.835 (gemeten met een losse per-bestandprobe
op alle zeven gate-varianten; kalenderbreed 13.835, alleen-duplicaat 15.195,
alleen-sprong 15.866, sprong+duplicaat 13.835).
Fixtures 22c/22d in `check-xer-calendar-data.ts` zijn exact de twee false positives;
tegen de kalenderbrede decoder gaan ze rood (2 afwijkingen, exit 1).
2. TWEE BLOKKEN ZONDER OPENINGSDUPLICAAT verantwoord. 2006-12-29 en 2009-09-18 dragen
geen duplicaat; ze worden door de SPRONG-vorm gedekt, niet meer impliciet door een
kalenderbrede vlag. Fixture 22b pint dat (2009-09-19 is een van de tien set-cover-dagen).
3. REIKWIJDTE eerlijk. Niet "23 records op één kalender": rehab-2 deelt zijn `clndr_data`
44× (groep van kalender 842) en 75× (groep van 896), dus 119 van de 124 kalenders
krijgen elk dezelfde 23 dagen — 2.737 dagvermeldingen. Taken staan alleen op de
842-groep (6.548 van de 6.977) en op kalender 893 (429); de 896-groep is takenloos.
4. BRONTOETS op de reconstructie (het antwoord op de ES/EF-vraag). Voor de 6.548 taken op
de 842-groep zet P6 in álle negen blokken — inclusief de gereconstrueerde weekenddagen —
NUL ES, EF, LS en LF, terwijl hij in de drie dagen direct vóór en ná de vier blokken die
in de projectperiode vallen 125 (okt-2008), 141 (dec-2008), 64 (sep-2009) en 78
(nov-2009) datums zet. De reconstructie is dus door de bron bevestigd. De 14 EF's op
2008-12-14 die op het eerste gezicht het tegendeel leken te bewijzen horen bij kalender
893 `R111 - 2`, een 7-daagse kalender zonder uitzonderingen die hier niet geraakt wordt.
5. BLOKABLATIE gedraaid (Plan §4.5), per as, op rehab-2:
basis 14.812 es 618 ef 813 ls 4358 lf 4350 tf 4200 ff 473
alle negen blokken 13.835 es 940 ef 940 ls 3889 lf 3889 tf 3903 ff 274
zonder dec-2008 13.314 es 620 ef 684 ls 3951 lf 3948 tf 3785 ff 326
zonder okt-2008 13.394 es 741 ef 785 ls 3890 lf 3890 tf 3753 ff 335
zonder sep-2009 14.672 zonder nov-2009 14.171 zonder okt+dec 13.451
Per LOSSE DAG weglaten is telkens fors slechter (14.5k–15.2k): een half gereconstrueerd
blok geeft datums die noch die van P6 noch de fysieke zijn. De vijf blokken buiten de
projectperiode (13 dagen) hebben exact nul effect.
KEUZE: alle negen blokken. `zonder dec-2008` scoort 521 cellen beter en zou de
ES-regressie wegnemen, maar punt 4 laat zien dat P6 juist rond dát blok 141 datums zet
en er géén ín — het blok vrij maken is brongetrouw. Een kalender bewust fout zetten om
celtellingen te kopen is geen model.
6. ES/EF-REGRESSIE als open residu benoemd, niet weggepoetst: 344 nieuw kapotte ES- en
327 nieuw kapotte EF-cellen (es 618→940, ef 813→940), 343 daarvan op de 842-groep,
281× één dag en 56× twee dagen te LAAT. Het is een forward-ANKER-gat, geen kalendergat:
voor `V3109400` telt het venster van P6 (2008-12-04 → 12-24) op de gereconstrueerde
kalender exact zeven werkdagen, en ons venster (12-06 → 12-25) óók — de duurwandeling
klopt dus, alleen het startanker ligt één werkdag later. De vijf getraceerde taken uit de
review (V3109400, V3109300, V3109420, V3109220, V3109480) zijn het startpunt voor die
vervolgetappe.
7. P6-XER-PENALTYPROJECTIE VERWIJDERD. Gemeten per bestand, met en zonder de projectie, op
alle zes penaltydragende corpusprojecten: rehab-2 13.835/13.835, Hotel Project 308/308,
Hotel_Construction_TEC 308/308, Roads_Project_TEC 1006/1006, p6_torture_test_v1 0/0,
Harbour Point As-Built 0/0, Harbour Point Baseline 93/93 — byte-identiek op alle zes de
assen. Ze verklaart nergens meer één cel. `subtractP6XerProjectedWorkMinutes`,
`p6XerProjectedWorkMinutesBetween` en hun solveraanroepen zijn weg; `CalendarEngine` kent
daarmee geen brongebonden asymmetrie meer en `check-calendar-mirror.ts` deel C pint dat
nu andersom. `WorkCalendar.p6NonWorkPenaltyDates` blijft als BRONDIAGNOSE bestaan (round-
trip door het IFC); geen solverpad leest het veld nog. De eerdere claim "voor twaalf andere
corpusbestanden nog steeds het enige model" was ongemeten en is hiermee ingetrokken; de
18.398 → 21.588 uit `fbcdb731` mat de schrapping van rehab-2's eigen klemdatums, niet een
generieke schrapping.
X12-PRODUCTFIDELITY, per bestand (`OPS_XER_FIDELITY_REPORT=baseline`):
totaal 18.398 → 17.421 (−977)
rehab-2.xer 14.812 → 13.835 (−977)
alle 28 overige bestanden ongewijzigd, 0 verschil
per as: es +322, ef +127, ls −469, lf −461, tf −297, ff −199
BASELINES. `xer-schedoptions-blast-radius.json` staat weer in zijn oorspronkelijke opmaak
(diff t.o.v. 7a3dece: 79/16 regels i.p.v. 311). Er bewegen 47 bladwaarden, allemaal
`deviations`-tellers in de tegenvariant-/causale takken: 45 omlaag (grootste
`completedProgress.rows.14` 7439 → 5248, `expectedFinishVariant.fidelity.*.ls` 8356 → 6176,
`.ef` 9121 → 7002) en 2 omhoog — en die twee zijn exact de ES/EF-assen van de
`xerDefaults`-tak (1062 → 1384 en 1287 → 1414), dezelfde +322/+127 als hierboven. De
124-kalenderdigest en de openbare task-replaypin bewegen mee met de nieuwe kalender.
GEEN OPMAAKRUIS: `git diff -w` is regel-voor-regel gelijk aan `git diff` (de CRLF-flip die
`7a3dece6` in `CalendarEngine.ts` meebracht is hier niet herhaald).
POORTEN. `OPS_XER_CORPUS=… npm run test:planning` exit 1 met uitsluitend: de drie
X12-nuldoelregels (totaal nu 17.421), de X12-regel die de v1-overgangsbaseline met de
v2-meting vergelijkt (al rood vóór deze etappe, ander schema), en
`milestone-duration-render`, dat op basiscommit a669108 al rood staat. 560/560 CPM-cases
groen; `mpp-fidelity` groen (2196 checks, 216 bestanden, netto ongewijzigd); X12 ZONDER
corpus groen (74 corpusloze checks), dus CI en deploy blijven groen. `npm run typecheck`
exit 0, `npm run lint` exit 0.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 1d1bc96)
…ring vastgelegd
Her-check-ronde op `1d1bc96d` (verdict GO-MET-DOSSIER-7b-4). Vijf voorwaarden afgewerkt.
1. RESTLEK GEDICHT. De reviewer vond twee nieuwe false positives op de record-lokale poort:
D — een za-do-kalender met twee LOSSE feestdagen die toevallig drie dagen uit elkaar
liggen (vr 2009-12-04 en ma 12-07) maakte via de sprongvorm zaterdag 12-05 half vrij;
F — een 7-daagse kalender met een tweedaags blok (do 12-03 + vr 12-04) waarvan de vrijdag
per ongeluk dubbel stond, maakte zaterdag 12-05 vrij.
`hasWeekendClampEvidence` eist nu drie dingen, alle drie lokaal:
(a) MEERDAAGS BLOK — de reeks rond het record telt minstens drie losse
uitzonderingsdatums (een gat van hoogstens drie dagen breekt de reeks niet, dat gat
ís het geklemde weekend). Sluit D én F. In rehab-2 tellen alle negen blokken 5–11.
(b) BLOKVERVOLG AAN DE VAN-HET-WEEKEND-AFGEKEERDE ZIJDE — de dag vóór een vrijdag of ná
een maandag draagt zelf ook een uitzondering; bij de sprongvorm volstaat dat één van
de twee sprongpartners dat doet (dat dekt de twee blokken die met een vrijdag zonder
voorganger openen: 2006-12-29 via ma 2007-01-01, 2009-09-18 via ma 2009-09-21).
(c) een van de twee bewijsvormen: de sprong, of een aangrenzend duplicaat.
Fixtures 22f (D) en 22g (F) zijn toegevoegd; tegen de decoder van `1d1bc96d` gaan ze beide
rood met exact de gemelde extra zaterdag (2 afwijkingen, exit 1).
De verscherping kost NUL cellen: rehab-2 blijft 13.835 op alle zes de assen (es 940,
ef 940, ls 3889, lf 3889, tf 3903, ff 274), 119 kalenders, dezelfde 23 datums per
kalender; X12-corpustotaal blijft 17.421 en alle andere bestanden byte-identiek.
2. BASELINE-OPMAAK. `xer-schedoptions-blast-radius.json` staat nu volledig in de
oorspronkelijke compacte vorm — `completedProgress` stond nog uitgeklapt omdat zes rijen
126 tekens tellen. Netto diff t.o.v. basiscommit `7a3dece6`: 47 toegevoegde en 47
verwijderde regels, en dat zijn precies de 47 veranderde `deviations`-waarden — nul
opmaakregels. (De eerdere "79/16" in `1d1bc96d` mat de diff t.o.v. `fbcdb731`, niet t.o.v.
de basis; de reviewer mat daar terecht 192/48.)
3. RANDDEFINITIE. De 125/141/64/78 uit `1d1bc96d` telde alleen ES en EF. De definitie staat
nu expliciet in het docblok — alle VIER de assen (ES, EF, LS, LF), over de 6.548 taken op
de gereconstrueerde kalendergroepen, waarbij de rand de drie kalenderdagen direct vóór de
eerste en direct ná de laatste dag van de GERECONSTRUEERDE blokspanne is — met de juiste
getallen: 167 (okt-2008, 153 taken), 214 (dec-2008, 193), 178 (sep-2009, 157), 252
(nov-2009, 204); 811 totaal tegen 0 datums ín de blokken. Reproduceert de meting van de
reviewer op de eenheid. De tweede bevestiging staat er nu ook bij: P6's eigen vensters
telden op de OUDE kalender 10,00 werkdagen voor `V3109400` (7 dagen duur) en 24,00 voor
`V3109300` (21 dagen), en op de gereconstrueerde exact 7,00 en 21,00.
4. PLAN-DOC. `docs/superpowers/plans/2026-08-20-plan-xer-p6-lezer.md` krijgt twee stukken:
§5 `X-O7` legt de regel "een fidelity-stap maakt geen as slechter" vast MÉT de expliciete,
eenmalige uitzondering voor deze etappe (es +322, ef +127) en de twee bronmetingen die
haar rechtvaardigen; §9 registreert dossier **7b-4 "forward-anker na gereconstrueerde
kalenderblokken"** met de 344/327 cellen, de vijf getraceerde taken, de vensterlengte-
tabel die aantoont dat de duurwandeling klopt, en de n=1-basis (één bestand van 93; MPXJ
kent het verschijnsel niet, dus een tweede bestand moet de regel bevestigen of ontkrachten
in plaats van er stil op mee te liften).
5. POORTEN. `npm run typecheck` exit 0, `npm run lint` exit 0,
`check-xer-calendar-data.ts` exit 0 (44 checks), `check-calendar-mirror.ts` exit 0 (80),
X12 summary mét corpus `17421` (exit 0 in meetmodus), `check-xer-schedule-options-corpus`
exit 0 (17), `check-xer-calendar-corpus` exit 0 (8), `check-xer-task-replay` exit 0 (32).
`git show -w` is regel-voor-regel gelijk aan `git show`.
NIET GEDAAN (bewust, staat als open punt): de `public/docs`/changelog-regel over het verschil
tussen een verse XER-import en een eerder opgeslagen IFC, en de
`readIFCWithXerReconstruction`-fixture uit H-3.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit a66ae13)
…innig Alleen commentaar, geen gedragswijziging. 1. `hasWeekendClampEvidence` zei impliciet dat de drie eisen de false-positive-klasse dichten. Ze dichten de twee GEMETEN gevallen (fixtures 22f en 22g), niet de klasse. Het docblok geeft nu het tegenvoorbeeld dat de klasse reproduceert: voeg aan 22f één dag toe — vrijdag 2009-12-04, maandag 12-07 én dinsdag 12-08 als losse feestdagen op een za-do-kalender — en de reeks haalt de drempel van drie, de maandag heeft blokvervolg aan zijn afgekeerde zijde, en zaterdag 12-05 wordt alsnog vrijgemaakt (nagemeten: `2009-12-04 2009-12-05 2009-12-07 2009-12-08`; zondag 12-06 niet, want een maandagrecord is op deze kalender geen redundant record). Met de vermelding dat het risico empirisch klein is — nul treffers in 93 corpusbestanden buiten `rehab-2.xer` — maar niet nul: de poort filtert op bewijskracht en is geen sluitend bewijs. 2. "Nul in alle negen blokken tegen 811 eromheen" suggereerde dat alle negen blokken bewijs dragen. In dezelfde zin staat nu dat die 811 volledig op de vier blokken binnen de projectperiode zit (167/214/178/252) en dat de overige vijf 0 ín én 0 in de rand hebben en dus niets bewijzen. Zelfde correctie in de X-O7-tekst in `docs/superpowers/plans/2026-08-20-plan-xer-p6-lezer.md`. Poort: `npm run typecheck` exit 0. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> (cherry picked from commit ae5931e)
…en gedrag) Ontwerp 2026-09-04 §4.1/§4.3/§4.4, bouwstap 1: - `Task.workRule` (WorkRule, neutraal tussen MSP en P6) en `Project.defaultWorkRule`; `ResourceAssignment.plannedWorkMinutes/ actualWorkMinutes/remainingWorkMinutes` (drie optionele werkvelden, besluit 9). Afwezig ⇒ afgeleid zoals vandaag; geen enkele solverstap of bewerking leest ze nog (dat is stap 4). - IFC: pset `OPS_WorkRule` (descriptor 15 in PER_TASK_PSETS), `DefaultWorkRule` in OPS_ProjectSettings, de drie werkvelden in het bestaande `OPS_Timephased`-JSON-blob (golden rule: niets ⇒ niets). Fixture + canon in check-ifc-roundtrip (185 groen). - Extensiecontract: ExtTask.workRule, ExtProject.defaultWorkRule, ExtAssignment-werkvelden, mappers beide kanten, contractpoort groen. - Taakraster: alleen-lezen technische kolommen `task.workRule` en `assignment.plannedWork/actualWork/remainingWork` (uren in beeld), labels in 14 locales; veld-dekking en registerpoort groen. - MCP: planner_get_task toont workRule en de werkvelden; REJECT_HINT voor workRule tot stap 7. moveProject-verdicten n/a. - Nieuw: `src/engine/work/workRuleMapping.ts` (stap 2, nog onbedraad): MSPDI-codes 0/1/2, P6 DurationType-namen, XER-tokens, en de "afwezig ⇒ afgeleid"-importregel voor de werkvelden. Planning-, MCP- en bibliotheeksuite groen; typecheck, cycles, store-boundaries, i18n groen. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159unb6VzxUx7WG4w3a2ARA
…in de taaktypes-branch Gestapelde branch: de taaktypes-etappe bouwt verder op de XER-lezer (`Task.p6DurationType`, `OPS_P6Progress`, het XER-bronarchief). Conflicten waren uitsluitend "beide kanten voegden toe" in dezelfde 21 bestanden (taak-/projecttypes, ifcPsets, ext-contract, rasterdekking, MCP-leestool, moveProject-verdicten, negen compacte locale-bestanden, de twee poorten); beide kanten zijn behouden. `OPS_WorkRule` is nu descriptor 17, ná `OPS_P6Progress` en `OPS_Summary`. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159unb6VzxUx7WG4w3a2ARA
…werkvelden Ontwerp 2026-09-04 §4.2/§4.3/§4.4, bouwstap 2 (ná de merge met de XER-branch): - `importNormalize.deriveImportedWorkRules`: één afleiding van `workRule` uit de bewaarde importvelden (MSP: mspTaskType+effortDriven; P6/XER: p6DurationType), aangeroepen in de .mpp-, MSPDI-, P6 XML- en XER-lezer. Importvelden blijven onaangeraakt; een bestaande regel wint. - MSPDI: lezer leest task-level <Type> (0/1/2) en <EffortDriven>, writer schrijft ze uit de werkregel (bewaard MSP-vinkje wint, beslispunt 8-B); toewijzingen: Work/ActualWork/RemainingWork ↔ de drie werkvelden, alleen bewaard bij afwijking van duur × inzet (`importedWorkFields`). - P6 XML: <DurationType> beide kanten; ActualUnits/PlannedUnits/ RemainingUnits (uren) ↔ werkvelden op hun alfabetische PMXML-plek. FIX: de XER-branch had de labels "Fixed Duration and Units" en "Fixed Duration and Units/Time" verwisseld (DT_FixedDUR2 resp. DT_FixedDrtn); gecorrigeerd volgens Oracle's XER Import/Export Data Map Guide, ook in check-xer-p6xml-parity (die nu de DurationType-uitzondering op de asymmetrie vastlegt). - XER: TASKRSRC target_qty / act_reg_qty + act_ot_qty / remain_qty → werkvelden, alleen bij afwijking (afspraak met de XER-etappe); materiaal buiten de driehoek; `XerResourceReadContext.taskWorkMinutes` optioneel. - Nieuw: `check-work-rule-mapping.ts` (37 checks: tabellen, afleiding, MSPDI-/P6 XML-round-trips, XER-fixture). Fidelity-poorten ongewijzigd groen (mpp 678, xer 47); spec §4.2 bijgewerkt. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159unb6VzxUx7WG4w3a2ARA
…n MCP-tweeling Brug src/engine/work/workRuleApply.ts tussen de domeinobjecten en de pure kern workTriangle.ts: captureTriangle vóór de mutatie, settle… erna, één terugschrijf (applyTriangleResult) van inzet, restwerk en — waar de regel dat wil — de taakduur (verricht deel + nieuwe rest; hele dagen in dagmodus). Bedraad in taskSlice.updateTask (+ nieuw setTaskWorkRule), resourceSlice.assignResource/updateAssignment/unassignResource (+ nieuw setAssignmentWork), gridTransaction.ts (celduur én de assignment-set-cel via AssignmentSettleOp) en createMcpTransactions.ts (alle tweelingen plus setAssignmentWork/setTaskWorkRule op de draft). Een duur die uit de driehoek komt zet scheduleStale, herschaalt contour + importsplits en wist het Z8-venster — precies als een duurbewerking. rescaleTaskContours krijgt een keepWork-parameter uit de effectieve werkregel (contourKeepsWork; zonder eigen workRule blijft de MSP-afleiding gelden). reconcileContourWork = besluit 3: verandert het restwerk van een toewijzing mét contour, dan zakt de hoogte mee, de as blijft. assignmentDayUnits krijgt opgeslagen werk als derde bron (data, curvevorm over de duur); zonder werkveld byte-identiek. Regressie: tests/planning/check-work-rule-store.ts (65 checks: standaardregel byte-identiek, FIXED_WORK/FIXED_DURATION_WORK in de store, contour meetlat 22/23, raster, MCP, vierde bron, undo in één stap = meetlat 28). Planning- en MCP-suites groen. Spec §10 (stap 4 gebouwd, stap 6 store-kant meegenomen), TODO (remainingTime-vraag, B1c-koppelpunt clearLevelingGaps) en CLAUDE.md bijgewerkt. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159unb6VzxUx7WG4w3a2ARA
Geen nieuwe tool; drie bestaande uitgebreid. planner_update_tasks en planner_add_tasks kennen `fields.workRule` (vier waarden of null = project- standaard): de allowlist in taskFields.ts levert hem apart van de kale veld-merge, zodat updateTasksCore ná de duurpatch draft.setTaskWorkRule aanroept — een gelijktijdige `duration` wordt onder de OUDE regel verwerkt en de nieuwe regel legt daarna het restwerk vast (spec §5 rij 6). Bij aanmaak is het een kaal veld; beide addTask-tweelingen nemen `workRule` mee. planner_manage_assignments `update` kent `remainingWorkMinutes` (> 0, via draft.setAssignmentWork; alleen waar workRuleApplies — mijlpaal/samenvatting/ hangmat/ELAPSEDTIME zacht geweigerd). planner_update_project kent `defaultWorkRule` (null ⇒ sleutel echt weg); planner_get_project_info toont hem. REJECT_HINTS voor de drie werkvelden als taakveld. tests/mcp/cases-work-rule.ts: 9 cases via de echte dispatch (zetten/wissen/ ongeldig, duur+regel in één call, FIXED_WORK vs standaardregel, resource erbij/eraf, projectstandaard, planner_batch = één undo-stap). Planning- en MCP-suites groen; spec §10, TODO en CLAUDE.md bijgewerkt. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159unb6VzxUx7WG4w3a2ARA
…ing, geen drift, verplaatsen/verwijderen door de driehoek Blokkerend (B1): `settleDurationEdit` vergeleek de RESTduur, waardoor een voortgangsbewerking (completion/remainingTime via raster of een gespreide time-tak) de inzet herrekende. De poort is nu de TOTALE werkduur uit de momentopname (`CapturedTriangle.totalMinutes`). Blokkerend (B2): een duur uit de driehoek op een gestarte taak liet de rest opnieuw afleiden als nieuwe duur × (1 − completion) ⇒ drift bij heen-en-weer (case 31). De rest wordt nu expliciet geschreven (`remainingTime`/ `remainingMinutes`) zodra de taak gestart is; `completion` blijft. Belangrijk (B3): de opgeslagen-werk-bron in `assignmentDayUnits` telt nu het verrichte deel mee (`actualWorkMinutes`, anders verrichte duur × inzet) — een typewissel op een half gedane taak halveerde anders het histogram. Belangrijk (B4): `moveAssignment` (eraf + erbij) en `removeResource` (eraf per taak) lopen door de driehoek, in store én MCP-tweeling. Klein: K1 `workRule` via `updateTask`/`updateTaskFields`/`patchTaskFields` legt via `settleRuleChange` óók het werk vast; K3 alleen een herleide inzet wordt afgerond; K4 één uurmodus-test (`isHourTask`) voor lezen en schrijven; K5 `settleDurationAftermath` als ene nazorg (contour, importsplits, Z8-venster, bevroren walks) voor store, raster en MCP; K6 volgorde in een gemengde Resources-cel gedocumenteerd en getest. K2 (kalenderwissel na vastgelegd werk) staat als open beslispunt in de TODO. Tests: check-work-rule-store 65 → 95 checks (voortgang > 0, uurmodus, FIXED_RATE + 8-B, materiaal in het raster, datums-zoals-opgeslagen, verplaatsen/resource verwijderen, K1). Planning- en MCP-suites groen. Spec §6.1/§6.5/§8/§10 en CLAUDE.md bijgewerkt. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159unb6VzxUx7WG4w3a2ARA
…iting, paneel/dialoog, raster, i18n en gids Zichtbaarheid (spec §7): instelling `ui.showTaskTypes` (`ops-showTaskTypes`, settingsRegistry + saveShowTaskTypes + SettingsPanelContent, default uit) óf documentontsluiting: `taskTypesVisible` in DOCUMENT_FIELDS (rol none, bij laden afgeleid via `hasTaskTypeData` — taak met workRule/mspTaskType/p6DurationType, projectstandaard, of toewijzing met werkveld — en gezet door setTaskWorkRule, setAssignmentWork en de rasterbewerkingen), met één melding per document (`taskTypesNotice.ts`, notifications.taskTypesUnlocked, helpArticleId → gids-taaktypes). Selector `taskTypesUnlocked` (engine/work/taskTypesVisibility). UI: `TaskWorkRuleField` in eigenschappenpaneel en taakdialoog (keuzelijst met projectstandaard, "Beschermd: …" in gewone woorden, MSP-bijschrift 8-B); in `TaskAssignmentsSection` de kolom Werk (rest) in uren met slotjes op de beschermde hoek en '—' voor materiaal; raster: `task.workRule` als bewerkbare enum (typewissel legt via gridTransaction het werk vast) en `assignment.remainingWork` als tokens-kolom "naam: uren" via de assignment-set- transactie en `settleWorkEdit`; beide alleen `available` wanneer ontsloten (`TaskColumnContext.taskTypesUnlocked`, ook in de gridtransactie-context). `task.workRule` leest in `readOnly` alleen gecertificeerde controllers en staat in de Aanbeveling-4-pin van check-grid-transaction; de plakbenchmark filtert op `available` zoals de echte adapter. i18n in 14 locales (workRule-namen, beschermingsteksten, instelling + hint, melding, kolomvalidatie); gids `gids-taaktypes` nl+en + manifest (README-telling 34); spec §10, TODO en CLAUDE.md bijgewerkt. Tests: check-work-rule-store sectie (n) (110 checks), browserspec tests/browser/work-rule.spec.ts (keuzelijst, werk typen, inzet, undo, ontsluiting; 3/3 groen), planning-/bibliotheek-/MCP-suites groen, verify:i18n, verify:docs, verify:examples groen. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159unb6VzxUx7WG4w3a2ARA
…erkt docs/superpowers/README.md: de spec staat nu als "gebouwd (stappen 1–7)" met de code-aanwijzers; docs/wiki/Features.md krijgt de feature "Task types and work" met link naar de gids gids-taaktypes. verify:docs groen. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159unb6VzxUx7WG4w3a2ARA
…bevriest niets, typewissel zonder stale, dialoog commit direct B1: `validateAssignmentTokens` laat `remainingWorkMinutes` meereizen bij plakken naar een andere taak (de genormaliseerde tokens lieten het werk vallen ⇒ stille no-op). B2: de werkcel in het raster vergelijkt met de GETOONDE waarde (opgeslagen, anders restduur × inzet) zodat een niet-bewerkte toewijzing haar afgeleide getal niet als expliciet werk krijgt. B3: de werkregel in het eigenschappenpaneel loopt via `setTaskWorkRule` — geen `scheduleStale`, "datums zoals opgeslagen" blijft staan. B4: in de taakdialoog commit een typewissel op een bestaande taak direct (zoals de toewijzings- sectie), en Opslaan stuurt de duur alleen mee wanneer de gebruiker die in de dialoog wijzigde (anders draaide Opslaan een duur uit de driehoek terug). K1: `clearTaskTypesNoticeForDoc` bij newProject/createNewProject. K3: elk schrijfpad (updateTask, addTask, MCP-tweelingen) ontsluit het document. K4: werkkolom en rasterkolom alleen waar `workRuleApplies`. K5: werkinvoer commit op Enter/blur (`WorkHoursInput`), niet per toetsaanslag. K6: contour- restsom als afgeleide waarde, aria-labels met resourcenaam, sectiekop in de instellingen (`settings.taskTypesSection`, 14 locales). MCP: `planner_manage_assignments` `add` kent `remainingWorkMinutes` (in een batch is het nieuwe assignmentId niet tempId-resolveerbaar). Tests: check-work-rule-store sectie (o) (120 checks), cases-work-rule 10, browserspec typt toets-voor-toets en dekt het dialoogpad (3/3). Planning- en MCP-suites groen. TODO (K2 crashherstel-melding, K6a) en spec §10. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159unb6VzxUx7WG4w3a2ARA
…r de werkregel, expliciete rest schuift mee K2 (spec §6.4 herzien): een andere kalender (taakkalender, projectkalender of andere uren per dag in een kalender) verandert de slotgrootte; de restduur in dagen blijft, het werk van vóór de wissel is het anker en daarna beslist de regel — Vast werk/Vaste inzet ⇒ R = max(W/I) in de nieuwe slot (langer bij minder uren per dag), Vaste duur en werk ⇒ inzet W/R', standaardregel ⇒ werk volgt (byte-identiek zonder werkveld). Kern `applySlotChange`, brug `settleCalendarChange`; bedraad in taskSlice.setTaskCalendar en updateTask (calendarId, vóór een eventuele duur in dezelfde patch), de rastercel Kalender, de MCP-tweelingen (updateTaskFields/patchTaskFields/updateCalendar), projectSlice.setProjectCalendar en resourceSlice.updateCalendar (alle taken op die kalender, `tasksOnCalendar`). Een project-/kalenderwijziging die duren verandert meldt hoeveel (notifications.workRuleDurationsChanged, 14 locales met CLDR-meervouden). Uurtaken blijven ongemoeid. Δ-rest (spec §6.5): een duurbewerking op een taak met EXPLICIETE restduur schuift die rest mee (rest = max(0, rest + Δ), dag- en uurmodus; completion blijft) — Microsoft: Remaining Duration = Duration − Actual Duration [M5]. `carryRemainingThroughDurationEdit` in updateTask, het raster (finishDurationEdit) en de MCP-tweeling, alleen wanneer de patch de rest niet zelf zette. Meetlat 32–34 (kern + spec §9, evidence reasoned met de Microsoft-/Oracle- bronnen); check-work-rule-store sectie (p) (142 checks); gids nl+en, TODO, CLAUDE.md. Planning-, MCP- en bibliotheeksuite groen. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159unb6VzxUx7WG4w3a2ARA
…g, contour-as op de oude slot, FIXED_RATE zonder werkveld Reviewbevindingen F1–F11 op fae46f3: - F1 raster: de kalendercel is een EIGEN stap vóór de rest van de paste (zelfde volgorde als `updateTask`); een `else` tussen kalender- en duurstap gooide de geplakte duur weg. - F2/F8 MCP `patchTaskFields`: Δ-rest- en contourreferentie ná het kalenderblok; `restUntouched`-poort. - F3: `captureCalendarChange` legt de werkminuten in de OUDE slot vast; `settleCalendarChange` doet nu zelf de nazorg (één definitie voor zes aanroepers) en herschaalt de contour-as óók wanneer de dagen niet veranderen (Vaste duur: dezelfde dagen zijn in de nieuwe slot ander werk). - F5 kern: `applySlotChange` legt onder FIXED_RATE geen werkveld vast (zoals `applyUnitsEdit`). - F6/F7: 8-B geldt niet bij een slotwissel; Δ-rest geldt wél op ELAPSEDTIME maar niet op verzameltaak/hangmat/mijlpaal — beide gedocumenteerd (spec §6.4/§6.5, docbloks). - F9: `tasksOnCalendar` via `resolveCalendar` (bungelende kalender volgt de projectkalender); `tasksFollowingProjectCalendar` voor `setProjectCalendar`. - F10: melding zonder dedupeKey — één melding per bewerking met het echte aantal. - F4: bewust niet gewijzigd (`completion` blijft); de inconsistentie met de Gantt-voortgangsbalk staat als open eigenaarsvraag in spec §6.5 en docs/TODO.md. - Extra: `setTaskCalendar`/`updateTask` meldden een door de nazorg gewist Z8-venster niet. Tests: sectie (r) in check-work-rule-store (22 checks), kern-cases 35/36 (meetlat 1…36), twee MCP-toolcases (update_tasks calendarId+duration, update_calendar). Alle suites groen. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159unb6VzxUx7WG4w3a2ARA
…te uit de toewijzing, effectieve slot, verliesmelding op alle paden - G1/G2: `settleCalendarChange` schaalt de contour-as éérst naar de nieuwe slot (hoogte volgt R' × I) en verzoent daarna de hoogte van elke contour met opgeslagen werkveld tegen dat werk (`reconcileContourWork` over alle toewijzingen van de taak) in plaats van tegen een regelvlag — onder de standaardregel schaalde de hoogte dubbel (histogram 25 % te laag), onder FIXED_RATE liepen contour en toewijzing uiteen. - G3: `applyCellEdits` gebruikt weer `assignmentsForTask` (gemeten: 746 → 129 ms bij 1000 taken × 1000 toewijzingen). - G4: `updateCalendar` en `setProjectCalendar` melden een door de nazorg gewist Z8-venster. - G5: `workRuleContextOf` en `taskCalendarHoursPerDay` lezen de EFFECTIEVE uren per dag (`effHoursPerDay`), dezelfde slot als het raster. - G6/G7/G9/G10: docblok `rescaleTaskContours` klopt weer met de code; ELAPSEDTIME blijft bij een kalenderwissel byte-identiek (spec §6.4); drie niet-bedrade randpaden en het Z8-venster-verschil in docs/TODO.md en CLAUDE.md. - G11: dode `docId`-parameter van `notifyWorkRuleDurationsChanged` weg. - G8: contour mét werkveld over alle vier de regels (hoogte = werk toewijzing, histogramsom) en de verliesmelding via updateCalendar/setProjectCalendar gepind (174 checks). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159unb6VzxUx7WG4w3a2ARA
…pliciet geschreven rest Zodra de brug de restduur expliciet schrijft (Δ-regel bij een duurbewerking, kalenderwissel op een gestarte taak) wordt `completion` herrekend als 1 − rest ÷ duur (`syncCompletionToRemaining`, dezelfde formule en randafspraken als een restbewerking in het taakraster), zodat Gantt-balk, solver en rapportage één waarheid delen. Voorbeeld: 10 d op 50 % → 6 u/dag onder Vast werk geeft 12 d, rest 7, 41,7 %; terug naar 8 u/dag weer 10 d, rest 5, 50 %. Een duur die onder het verrichte deel wordt gekort geeft rest 0 en dus 100 %. Let op (spec §6.5): elke voortgangsinvoer en elke import schrijft `remainingTime` expliciet (`applyProgressInvariants`, `importNormalize`), dus de Δ-regel en dit besluit gelden in de praktijk voor vrijwel elke gestarte taak — een duurbewerking op een gestarte taak verandert het percentage. Tests: check-work-rule-store q1/q2/q6/q7/r4/r11/r12/r14, cases-work-rule en cases-taskfields bijgewerkt; spec §6.4/§6.5, docs/TODO.md, CLAUDE.md en de gids (nl+en). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159unb6VzxUx7WG4w3a2ARA
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
Het ontwerp
docs/superpowers/specs/2026-09-04-spec-taaktypes-opgeslagen-werk.md(opvolger van het voorstel van 2026-08-18; MS Project en P6 naast elkaar met bronnen, elke bewering gelabeld zeker/gemeten/afgeleid/beredeneerd/onbekend/besloten; eigenaarsbesluiten 1–10 in §3) en daaruit alle bouwstappen 1 t/m 8 volgens §10:Task.workRule(FIXED_DURATION_RATE = het gedrag van vandaag | FIXED_DURATION_WORK | FIXED_WORK | FIXED_RATE),Project.defaultWorkRule, drie optionele werkvelden per toewijzing; IFC-round-trip, documentcontract, extensiecontract alleen-lezen, alleen-lezen rasterkolommen,planner_get_task.<Type>/<EffortDriven>+ Work-velden; P6 XML<DurationType>(labelverwisseling van de twee Fixed-Duration-vormen gecorrigeerd, bron: Oracle XER Data Map Guide) + Units; XERduration_type+target_qty/act_*_qty/remain_qty. "Afwezig ⇒ afgeleid". Fidelity-poort blijft 0.src/engine/work/workTriangle.tsop de resterende toestand (W en I opgeslagen, R afgeleid en naar boven afgerond), meetlatwork-triangle-cases.json(44 cases over 36 bewerkingen).workRuleApply.tsintaskSlice,resourceSlice(ookmoveAssignment/removeResource),gridTransaction.tsen de MCP-tweeling; een duur uit de driehoek zetscheduleStaleen loopt doorsettleDurationAftermath; "vorm blijft, hoogte zakt" voor contouren;assignmentDayUnitskrijgt opgeslagen werk als bron.ops-showTaskTypes, default uit) óf documentontsluiting (taskTypesVisible, afgeleid bij laden, één melding met gids-link).TaskWorkRuleFieldin paneel en dialoog, kolom Werk (rest) met slotjes in de toewijzingstabel (commit op Enter/blur), rasterkolommentask.workRuleenassignment.remainingWork(alleen wanneer ontsloten). i18n 14 locales, gidsgids-taaktypesnl+en.planner_update_tasks/planner_add_tasksfields.workRule,planner_manage_assignmentsadd/updateremainingWorkMinutes,planner_update_projectdefaultWorkRule;planner_get_project_infotoont de projectstandaard.docs/superpowers/README.md, wiki-featurelijst, CLAUDE.md.fae46f3e). (K2) Een kalenderwissel verandert de slotgrootte en loopt daarna door de werkregel: onder Vast werk/Vaste inzet wordt de taak langer bij minder uren per dag, onder Vaste duur en werk stijgt de inzet, onder de standaardregel blijft alles zoals vandaag; een project-/kalenderwijziging die duren verandert meldt hoeveel (meetlat 32–34). (Δ-rest) Een duurbewerking op een taak met expliciete restduur schuift die rest mee (geklemd op 0), naar Microsofts identiteit Remaining Duration = Duration − Actual Duration.f72a964e). Kalender én duur in één rasterpaste of één MCP-call verloren de duur resp. het verrichte deel (F1/F2: de kalenderstap is overal een eigen stap vóór de rest); de contour-as werd tegen de nieuwe in plaats van de oude slot herschaald (F3:captureCalendarChange/settleCalendarChangeals één definitie voor zes aanroepers, inclusief herschaling wanneer de dagen niet veranderen); FIXED_RATE legde bij een slotwissel een werkveld vast (F5); 8-B en de reikwijdte van de Δ-regel gedocumenteerd (F6/F7);restUntouched-poort in de MCP-tweeling (F8); bungelende taakkalender volgt de projectkalender (F9); melding zonder dedupe-badge (F10); meetlat 35/36 (F11).d3bfc956). De as-herschaling schaalde de contourhoogte onder de standaardregel dubbel (histogram 25 % te laag) en liet onder FIXED_RATE contour en toewijzing uiteenlopen (G1/G2: de hoogte wordt nu tegen het werkelijke werk per toewijzing verzoend, niet tegen een regelvlag); eenstate.assignments.filterin de plakloop kostte 746 → 129 ms bij 1000 × 1000 (G3);updateCalendar/setProjectCalendarmeldden een gewist Z8-venster niet (G4); werkdriehoek en contourreferentie lezen nu de effectieve uren per dag zoals het raster (G5); docbloks en spec bijgewerkt, drie niet-bedrade randpaden indocs/TODO.md(G6/G7/G9/G10).c5fca94a). Zodra de brug de rest expliciet schrijft (Δ-regel of kalenderwissel op een gestarte taak) volgtcompletiondaaruit als 1 − rest ÷ duur (syncCompletionToRemaining, dezelfde formule als een restbewerking in het raster), zodat Gantt-balk, solver en rapportage één waarheid delen. Voorbeeld: 10 d op 50 % → 6 u/dag onder Vast werk geeft 12 d, rest 7, 41,7 %; terug naar 8 u/dag weer 10 d, rest 5, 50 %. Let op: elke voortgangsinvoer en elke import schrijftremainingTimeexpliciet (applyProgressInvariants,importNormalize), dus een duurbewerking op vrijwel elke gestarte taak laat het verrichte deel staan en verandert het percentage (spec §6.5).Vier onafhankelijke reviewrondes (bedrading; UI+MCP; K2/Δ-rest; de fix daarop), elk in een eigen fix-commit verwerkt (
7d4f2bfc,4016ebe8,f72a964e,d3bfc956).Onder de standaardregel zonder werkvelden en met de instelling uit is de app byte-identiek aan vandaag, met één uitzondering sinds de besluiten van 2026-09-05/06: een duurbewerking op een gestarte taak houdt het verrichte deel vast en herrekent het percentage. Open punten (spec §12 / TODO): MS Project-meting van de meetlat (incl. 32–36 en de Δ-regel), K2 op drie randpaden (G9), per-toewijzing-spanne, projectstandaard in de UI, crashherstel zonder melding.
Buiten de etappe:
check-milestone-duration-render.tsklikt op de getekende balk in plaats van een vaste x (weekend-flake).How it was verified
npm run verifygroen op de eindboom vóór commitfae46f3e(één browserspec,just-updated-dialog.spec.ts, faalt lokaal alleen opERR_CERT_AUTHORITY_INVALIDvan de sandbox-proxy en raakt deze etappe niet); daarna per commit:typecheck,lint,verify:cycles,verify:store-boundaries,verify:gantt-boundaries,verify:i18n,verify:docs, planningssuite 560/560 + tijdzone-matrix, bibliotheek- en MCP-suite (40/40); browserspecswork-rule.spec.ts(3/3) +contour-dialog.spec.ts. Nieuwe checks:check-work-triangle(370),check-work-rule-mapping(37),check-work-rule-store(174),tests/mcp/cases-work-rule.ts(12).Does this touch
docs/ifc-round-trip.md-route gevolgd, canon + fixtures uitgebreid);taskTypesVisibleis bewust sessie-afgeleid (rolnone).@tauri-apps/*— nee.Documentation
Spec (status en verwerkte reviewbevindingen per stap in §10; §6.4/§6.5 herzien voor de besluiten en de reviewrondes daarop),
docs/superpowers/README.md,docs/TODO.md, CLAUDE.md-alinea bij de contour-engine, in-app gidsgids-taaktypes(nl+en; 12 vertalingen volgen maandelijks),docs/wiki/Features.md.🤖 Generated with Claude Code
https://claude.ai/code/session_0159unb6VzxUx7WG4w3a2ARA