Page MenuHomeWildfire Games

Avoid GUI errors for captured buildings with paired techs of a different civ
ClosedPublic

Authored by elexis on Aug 12 2019, 4:57 AM.

Details

Summary

If there is a building that has a paired tech researchable, where the two techs have a civ requirement but the parent pair tech doesn't, then the selection panels will throw errors.
This has happened with rP18653, https://wildfiregames.com/forum/index.php?/topic/24732-de-alpha-24/page/2/, and other incidences.
It should not throw an error but handle it more gracefully.

Test Plan

Dig through the tech parsing maze. Consider whether returning false for unmet civ requirements still makes sense over returning an array. Conclude that the GUI is the one making assumptions that are not always true, or at least should be handled gracefully if not met, rather than the tech req parsing code being in the wrong.
Figure something out about the indentation.

The issue can be tested by:

  1. removing the requirements from pair_unlock_champions.json
  2. starting a cheat game with sele and non-sele
  3. "gift from the gods" cheat to fast build and age 3
  4. build fortress with sele
  5. alt+d / change perspective to brit, reveal map
  6. select fortress, type "wololo" to capture it

Result are errors, expected result are no errors and a happy panel.

Diff Detail

Repository
rP 0 A.D. Public Repository
Lint
Automatic diff as part of commit; lint not applicable.
Unit
Automatic diff as part of commit; unit tests not applicable.

Event Timeline

elexis created this revision.Aug 12 2019, 4:57 AM

Successful build - Chance fights ever on the side of the prudent.

Linter detected issues:
Executing section Source...
Executing section JS...
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 5 tabs but found 4.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 721| 721| 				let reqs = template.reqs;
| 722| 722| 
| 723| 723| 				if (reqs)
| 724|    |-				for (let req of reqs)
|    | 724|+					for (let req of reqs)
| 725| 725| 				{
| 726| 726| 					if (!req.entities)
| 727| 727| 						continue;
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 5 tabs but found 4.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 722| 722| 
| 723| 723| 				if (reqs)
| 724| 724| 				for (let req of reqs)
| 725|    |-				{
|    | 725|+					{
| 726| 726| 					if (!req.entities)
| 727| 727| 						continue;
| 728| 728| 
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 6 tabs but found 5.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 723| 723| 				if (reqs)
| 724| 724| 				for (let req of reqs)
| 725| 725| 				{
| 726|    |-					if (!req.entities)
|    | 726|+						if (!req.entities)
| 727| 727| 						continue;
| 728| 728| 
| 729| 729| 					let entityCounts = [];
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 7 tabs but found 6.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 724| 724| 				for (let req of reqs)
| 725| 725| 				{
| 726| 726| 					if (!req.entities)
| 727|    |-						continue;
|    | 727|+							continue;
| 728| 728| 
| 729| 729| 					let entityCounts = [];
| 730| 730| 					for (let entity of req.entities)
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 6 tabs but found 5.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 726| 726| 					if (!req.entities)
| 727| 727| 						continue;
| 728| 728| 
| 729|    |-					let entityCounts = [];
|    | 729|+						let entityCounts = [];
| 730| 730| 					for (let entity of req.entities)
| 731| 731| 					{
| 732| 732| 						let current = 0;
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 6 tabs but found 5.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 727| 727| 						continue;
| 728| 728| 
| 729| 729| 					let entityCounts = [];
| 730|    |-					for (let entity of req.entities)
|    | 730|+						for (let entity of req.entities)
| 731| 731| 					{
| 732| 732| 						let current = 0;
| 733| 733| 						switch (entity.check)
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 6 tabs but found 5.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 728| 728| 
| 729| 729| 					let entityCounts = [];
| 730| 730| 					for (let entity of req.entities)
| 731|    |-					{
|    | 731|+						{
| 732| 732| 						let current = 0;
| 733| 733| 						switch (entity.check)
| 734| 734| 						{
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 7 tabs but found 6.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 729| 729| 					let entityCounts = [];
| 730| 730| 					for (let entity of req.entities)
| 731| 731| 					{
| 732|    |-						let current = 0;
|    | 732|+							let current = 0;
| 733| 733| 						switch (entity.check)
| 734| 734| 						{
| 735| 735| 						case "count":
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 7 tabs but found 6.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 730| 730| 					for (let entity of req.entities)
| 731| 731| 					{
| 732| 732| 						let current = 0;
| 733|    |-						switch (entity.check)
|    | 733|+							switch (entity.check)
| 734| 734| 						{
| 735| 735| 						case "count":
| 736| 736| 							current = playerState.classCounts[entity.class] || 0;
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 7 tabs but found 6.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 731| 731| 					{
| 732| 732| 						let current = 0;
| 733| 733| 						switch (entity.check)
| 734|    |-						{
|    | 734|+							{
| 735| 735| 						case "count":
| 736| 736| 							current = playerState.classCounts[entity.class] || 0;
| 737| 737| 							break;
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 7 tabs but found 6.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 732| 732| 						let current = 0;
| 733| 733| 						switch (entity.check)
| 734| 734| 						{
| 735|    |-						case "count":
|    | 735|+							case "count":
| 736| 736| 							current = playerState.classCounts[entity.class] || 0;
| 737| 737| 							break;
| 738| 738| 
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 8 tabs but found 7.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 733| 733| 						switch (entity.check)
| 734| 734| 						{
| 735| 735| 						case "count":
| 736|    |-							current = playerState.classCounts[entity.class] || 0;
|    | 736|+								current = playerState.classCounts[entity.class] || 0;
| 737| 737| 							break;
| 738| 738| 
| 739| 739| 						case "variants":
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 8 tabs but found 7.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 734| 734| 						{
| 735| 735| 						case "count":
| 736| 736| 							current = playerState.classCounts[entity.class] || 0;
| 737|    |-							break;
|    | 737|+								break;
| 738| 738| 
| 739| 739| 						case "variants":
| 740| 740| 							current = playerState.typeCountsByClass[entity.class] ?
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 7 tabs but found 6.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 736| 736| 							current = playerState.classCounts[entity.class] || 0;
| 737| 737| 							break;
| 738| 738| 
| 739|    |-						case "variants":
|    | 739|+							case "variants":
| 740| 740| 							current = playerState.typeCountsByClass[entity.class] ?
| 741| 741| 								Object.keys(playerState.typeCountsByClass[entity.class]).length : 0;
| 742| 742| 							break;
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 8 tabs but found 7.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 737| 737| 							break;
| 738| 738| 
| 739| 739| 						case "variants":
| 740|    |-							current = playerState.typeCountsByClass[entity.class] ?
|    | 740|+								current = playerState.typeCountsByClass[entity.class] ?
| 741| 741| 								Object.keys(playerState.typeCountsByClass[entity.class]).length : 0;
| 742| 742| 							break;
| 743| 743| 						}
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 9 tabs but found 8.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 738| 738| 
| 739| 739| 						case "variants":
| 740| 740| 							current = playerState.typeCountsByClass[entity.class] ?
| 741|    |-								Object.keys(playerState.typeCountsByClass[entity.class]).length : 0;
|    | 741|+									Object.keys(playerState.typeCountsByClass[entity.class]).length : 0;
| 742| 742| 							break;
| 743| 743| 						}
| 744| 744| 
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 8 tabs but found 7.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 739| 739| 						case "variants":
| 740| 740| 							current = playerState.typeCountsByClass[entity.class] ?
| 741| 741| 								Object.keys(playerState.typeCountsByClass[entity.class]).length : 0;
| 742|    |-							break;
|    | 742|+								break;
| 743| 743| 						}
| 744| 744| 
| 745| 745| 						let remaining = entity.number - current;
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 7 tabs but found 6.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 740| 740| 							current = playerState.typeCountsByClass[entity.class] ?
| 741| 741| 								Object.keys(playerState.typeCountsByClass[entity.class]).length : 0;
| 742| 742| 							break;
| 743|    |-						}
|    | 743|+							}
| 744| 744| 
| 745| 745| 						let remaining = entity.number - current;
| 746| 746| 						if (remaining < 1)
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 7 tabs but found 6.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 742| 742| 							break;
| 743| 743| 						}
| 744| 744| 
| 745|    |-						let remaining = entity.number - current;
|    | 745|+							let remaining = entity.number - current;
| 746| 746| 						if (remaining < 1)
| 747| 747| 							continue;
| 748| 748| 
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 7 tabs but found 6.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 743| 743| 						}
| 744| 744| 
| 745| 745| 						let remaining = entity.number - current;
| 746|    |-						if (remaining < 1)
|    | 746|+							if (remaining < 1)
| 747| 747| 							continue;
| 748| 748| 
| 749| 749| 						entityCounts.push(sprintf(translatePlural("%(number)s entity of class %(class)s", "%(number)s entities of class %(class)s", remaining), {
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 8 tabs but found 7.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 744| 744| 
| 745| 745| 						let remaining = entity.number - current;
| 746| 746| 						if (remaining < 1)
| 747|    |-							continue;
|    | 747|+								continue;
| 748| 748| 
| 749| 749| 						entityCounts.push(sprintf(translatePlural("%(number)s entity of class %(class)s", "%(number)s entities of class %(class)s", remaining), {
| 750| 750| 							"number": remaining,
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 7 tabs but found 6.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 746| 746| 						if (remaining < 1)
| 747| 747| 							continue;
| 748| 748| 
| 749|    |-						entityCounts.push(sprintf(translatePlural("%(number)s entity of class %(class)s", "%(number)s entities of class %(class)s", remaining), {
|    | 749|+							entityCounts.push(sprintf(translatePlural("%(number)s entity of class %(class)s", "%(number)s entities of class %(class)s", remaining), {
| 750| 750| 							"number": remaining,
| 751| 751| 							"class": entity.class
| 752| 752| 						}));
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 8 tabs but found 7.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 747| 747| 							continue;
| 748| 748| 
| 749| 749| 						entityCounts.push(sprintf(translatePlural("%(number)s entity of class %(class)s", "%(number)s entities of class %(class)s", remaining), {
| 750|    |-							"number": remaining,
|    | 750|+								"number": remaining,
| 751| 751| 							"class": entity.class
| 752| 752| 						}));
| 753| 753| 					}
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 8 tabs but found 7.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 748| 748| 
| 749| 749| 						entityCounts.push(sprintf(translatePlural("%(number)s entity of class %(class)s", "%(number)s entities of class %(class)s", remaining), {
| 750| 750| 							"number": remaining,
| 751|    |-							"class": entity.class
|    | 751|+								"class": entity.class
| 752| 752| 						}));
| 753| 753| 					}
| 754| 754| 
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 7 tabs but found 6.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 749| 749| 						entityCounts.push(sprintf(translatePlural("%(number)s entity of class %(class)s", "%(number)s entities of class %(class)s", remaining), {
| 750| 750| 							"number": remaining,
| 751| 751| 							"class": entity.class
| 752|    |-						}));
|    | 752|+							}));
| 753| 753| 					}
| 754| 754| 
| 755| 755| 					tip += " " + sprintf(translate("Remaining: %(entityCounts)s"), {
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 6 tabs but found 5.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 750| 750| 							"number": remaining,
| 751| 751| 							"class": entity.class
| 752| 752| 						}));
| 753|    |-					}
|    | 753|+						}
| 754| 754| 
| 755| 755| 					tip += " " + sprintf(translate("Remaining: %(entityCounts)s"), {
| 756| 756| 						"entityCounts": entityCounts.join(translateWithContext("Separator for a list of entity counts", ", "))
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 6 tabs but found 5.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 752| 752| 						}));
| 753| 753| 					}
| 754| 754| 
| 755|    |-					tip += " " + sprintf(translate("Remaining: %(entityCounts)s"), {
|    | 755|+						tip += " " + sprintf(translate("Remaining: %(entityCounts)s"), {
| 756| 756| 						"entityCounts": entityCounts.join(translateWithContext("Separator for a list of entity counts", ", "))
| 757| 757| 					});
| 758| 758| 				}
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 7 tabs but found 6.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 753| 753| 					}
| 754| 754| 
| 755| 755| 					tip += " " + sprintf(translate("Remaining: %(entityCounts)s"), {
| 756|    |-						"entityCounts": entityCounts.join(translateWithContext("Separator for a list of entity counts", ", "))
|    | 756|+							"entityCounts": entityCounts.join(translateWithContext("Separator for a list of entity counts", ", "))
| 757| 757| 					});
| 758| 758| 				}
| 759| 759| 				tooltips.push(tip);
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 6 tabs but found 5.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 754| 754| 
| 755| 755| 					tip += " " + sprintf(translate("Remaining: %(entityCounts)s"), {
| 756| 756| 						"entityCounts": entityCounts.join(translateWithContext("Separator for a list of entity counts", ", "))
| 757|    |-					});
|    | 757|+						});
| 758| 758| 				}
| 759| 759| 				tooltips.push(tip);
| 760| 760| 			}
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 5 tabs but found 4.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 755| 755| 					tip += " " + sprintf(translate("Remaining: %(entityCounts)s"), {
| 756| 756| 						"entityCounts": entityCounts.join(translateWithContext("Separator for a list of entity counts", ", "))
| 757| 757| 					});
| 758|    |-				}
|    | 758|+					}
| 759| 759| 				tooltips.push(tip);
| 760| 760| 			}
| 761| 761| 			tooltips.push(getNeededResourcesTooltip(neededResources));
|    | [NORMAL] ESLintBear (space-before-function-paren):
|    | Unexpected space before function parentheses.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 765| 765| 				addResearchToQueue(data.item.researchFacilityId, t);
| 766| 766| 			})(tech);
| 767| 767| 
| 768|    |-			button.onPressRight = (t => function () {
|    | 768|+			button.onPressRight = (t => function() {
| 769| 769| 				showTemplateDetails(
| 770| 770| 					t,
| 771| 771| 					GetTemplateData(data.unitEntStates.find(state => state.id == data.item.researchFacilityId).template).nativeCiv);

binaries/data/mods/public/gui/session/selection_panels.js
|  48| »   »   »   switch·(data.item)
|    | [NORMAL] ESLintBear (default-case):
|    | Expected a default case.

binaries/data/mods/public/gui/session/selection_panels.js
|  59| »   »   switch·(data.item)
|    | [NORMAL] ESLintBear (default-case):
|    | Expected a default case.

binaries/data/mods/public/gui/session/selection_panels.js
| 733| »   »   »   »   »   »   switch·(entity.check)
|    | [NORMAL] ESLintBear (default-case):
|    | Expected a default case.
Executing section cli...

Link to build: https://jenkins.wildfiregames.com/job/docker-differential/361/display/redirect

Imarok added a subscriber: Imarok.Dec 18 2019, 6:44 PM

The patches fixes the bug.
But it seems it reveals a new one.
With your test plan and the patch the paired tech is greyed out and says this tech will be unlocked in city phase...

@Imarok's finding can probably be fixed by not showing techs from another civ.

I'll look into this.

Freagarach updated this revision to Diff 15246.Wed, Jan 13, 1:15 PM

A bit more elaborate fix, though still a tad ugly.

Owners added a subscriber: Restricted Owners Package.Wed, Jan 13, 1:15 PM

Build has FAILED

builderr-debug-macos.txt
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib: file: ../../../binaries/system/libsimulation2_dbg.a(precompiled.o) has no symbols
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib: file: ../../../binaries/system/libengine_dbg.a(precompiled.o) has no symbols
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib: file: ../../../binaries/system/libgraphics_dbg.a(precompiled.o) has no symbols
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib: file: ../../../binaries/system/libatlas_dbg.a(precompiled.o) has no symbols
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib: file: ../../../binaries/system/libgui_dbg.a(precompiled.o) has no symbols
ld: warning: text-based stub file /System/Library/Frameworks//CoreAudio.framework/CoreAudio.tbd and library file

Link to build: https://jenkins.wildfiregames.com/job/macos-differential/2832/display/redirect
See console output for more information: https://jenkins.wildfiregames.com/job/macos-differential/2832/display/redirectconsole

Freagarach updated the Trac tickets for this revision.Wed, Jan 13, 1:33 PM
This revision was not accepted when it landed; it landed in state Needs Review.Fri, Jan 15, 9:55 AM
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.